├── packages ├── .properties ├── TWM-GUI │ ├── package.st │ ├── MenuMorph.extension.st │ ├── Workspace.extension.st │ ├── TWMDockingBarMorph.class.st │ ├── TWMUpdatingMenuMorph.class.st │ ├── TWMBarButtonBuilder.class.st │ ├── TWMSettings.class.st │ ├── TWMWorldSnapshotBrowser.class.st │ ├── TWMDockingWindowMorph.class.st │ └── TWMBar.class.st ├── TWM-Core │ ├── package.st │ ├── Morph.extension.st │ ├── SystemWindow.extension.st │ ├── TWMLayoutStrategy.class.st │ ├── PasteUpMorph.extension.st │ ├── TWMVerticalLayoutStrategy.class.st │ ├── TWMHorizontalLayoutStrategy.class.st │ ├── TWMWorldSnapshot.class.st │ ├── TWMWindowSnapshot.class.st │ ├── TWMWorldRecorder.class.st │ ├── TWMWorldManager.class.st │ └── TilingWM.class.st ├── TWM-Tests │ ├── package.st │ ├── EyeInspectorThatFixesInitialExtentForTesting.class.st │ ├── WMWithNoWindowsTest.class.st │ ├── WMWithAnOBBrowserAndDockingBarsTest.class.st │ ├── TWMTestHelpers.trait.st │ ├── WMWhenTopWindowIsNilTestCase.class.st │ ├── WMInANewWorldTestCase.class.st │ ├── WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest.class.st │ ├── TWMBarWithTwoBrowsersAndTwoWorkspacesTest.class.st │ ├── WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest.class.st │ ├── TWMWindowSnapshotOfFinderTest.class.st │ ├── TWMBarInANewWorldTest.class.st │ ├── WMWithInspectorTranscriptAndMonticello.class.st │ └── WMWithTwoBrowsersAndTwoWorkspacesTest.class.st ├── TWM-Theme │ ├── package.st │ ├── SettingBrowser.extension.st │ ├── StandardTabPanelBorder.class.st │ ├── TWMUIThemeIcons.class.st │ └── TWMUITheme.class.st ├── TWM-KeyMapping │ ├── package.st │ └── TWMKeymapping.class.st ├── BaselineOfTilingWindowManager │ ├── package.st │ └── BaselineOfTilingWindowManager.class.st ├── .filetree └── ConfigurationOfTilingWindowManager │ ├── package.st │ └── ConfigurationOfTilingWindowManager.class.st ├── README.md └── LICENSE /packages/.properties: -------------------------------------------------------------------------------- 1 | { 2 | #format : #tonel 3 | } -------------------------------------------------------------------------------- /packages/TWM-GUI/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #'TWM-GUI' } 2 | -------------------------------------------------------------------------------- /packages/TWM-Core/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #'TWM-Core' } 2 | -------------------------------------------------------------------------------- /packages/TWM-Tests/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #'TWM-Tests' } 2 | -------------------------------------------------------------------------------- /packages/TWM-Theme/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #'TWM-Theme' } 2 | -------------------------------------------------------------------------------- /packages/TWM-KeyMapping/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #'TWM-KeyMapping' } 2 | -------------------------------------------------------------------------------- /packages/BaselineOfTilingWindowManager/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #BaselineOfTilingWindowManager } 2 | -------------------------------------------------------------------------------- /packages/.filetree: -------------------------------------------------------------------------------- 1 | {"packageExtension" : ".package", 2 | "propertyFileExtension" : ".json", 3 | "Metadata" : "false" } -------------------------------------------------------------------------------- /packages/ConfigurationOfTilingWindowManager/package.st: -------------------------------------------------------------------------------- 1 | Package { #name : #ConfigurationOfTilingWindowManager } 2 | -------------------------------------------------------------------------------- /packages/TWM-Theme/SettingBrowser.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : #SettingBrowser } 2 | 3 | { #category : #'*twm-theme' } 4 | SettingBrowser class >> patchworkUIThemeColor [ 5 | ^ Color paleMagenta 6 | ] 7 | -------------------------------------------------------------------------------- /packages/TWM-Core/Morph.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : #Morph } 2 | 3 | { #category : #'*TWM-Core' } 4 | Morph >> moveToWorldNamed: aString [ 5 | 6 | | destination | 7 | destination := TWMWorldManager instance worldNamed: aString. 8 | destination addMorph: self. 9 | ] 10 | -------------------------------------------------------------------------------- /packages/TWM-GUI/MenuMorph.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : #MenuMorph } 2 | 3 | { #category : #'*twm-gui' } 4 | MenuMorph >> add: aString target: aReceiver selector: aSelector icon: aForm [ 5 | self 6 | add: aString 7 | target: aReceiver 8 | selector: aSelector. 9 | 10 | self lastItem icon: aForm. 11 | ] 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # TilingWindowManager 2 | Pharo Tiling Window Manager 3 | 4 | ```Smalltalk 5 | Metacello new 6 | githubUser: 'pharophile' 7 | project: 'TilingWindowManager' 8 | commitish: 'master' 9 | path: 'packages'; 10 | baseline: 'TilingWindowManager'; 11 | onWarningLog; 12 | load 13 | ``` 14 | -------------------------------------------------------------------------------- /packages/TWM-Tests/EyeInspectorThatFixesInitialExtentForTesting.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #EyeInspectorThatFixesInitialExtentForTesting, 3 | #superclass : #EyeInspector, 4 | #category : 'TWM-Tests' 5 | } 6 | 7 | { #category : #'as yet unclassified' } 8 | EyeInspectorThatFixesInitialExtentForTesting >> initialExtent [ 9 | ^ 200@200 10 | ] 11 | -------------------------------------------------------------------------------- /packages/TWM-GUI/Workspace.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : #Workspace } 2 | 3 | { #category : #'*twm-gui' } 4 | Workspace >> contentsFirstLine [ 5 | 6 | | lines textMorph| 7 | self flag: #TODO. "Works with old workspace, not so well with Playgrounds. To fix." 8 | textMorph := self dependents detect: [:c | c isKindOf: PluggableTextMorph] ifNone: [nil]. 9 | ^ textMorph 10 | ifNotNil: [ lines := textMorph text asString lines. 11 | lines ifEmpty: [''] ifNotEmpty: [lines first] ] 12 | ifNil: ['']. 13 | ] 14 | -------------------------------------------------------------------------------- /packages/TWM-Core/SystemWindow.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : #SystemWindow } 2 | 3 | { #category : #'*twm-core' } 4 | SystemWindow >> expandAndActivate [ 5 | self 6 | show; 7 | expand; 8 | comeToFront; 9 | activate. 10 | ] 11 | 12 | { #category : #'*twm-core' } 13 | SystemWindow >> printOn: aStream [ 14 | 15 | self model 16 | ifNil: [super printOn: aStream] 17 | ifNotNil: [aStream 18 | nextPutAll: self className; 19 | nextPutAll:' for ['. 20 | self model printOn: aStream. 21 | aStream nextPutAll: '] ('; 22 | print: self identityHash; 23 | nextPutAll: ')' ]. 24 | ] 25 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMDockingBarMorph.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a DockingBar that dynamically update its submenus when they are opened 3 | 4 | " 5 | Class { 6 | #name : #TWMDockingBarMorph, 7 | #superclass : #DockingBarMorph, 8 | #category : 'TWM-GUI' 9 | } 10 | 11 | { #category : #control } 12 | TWMDockingBarMorph >> activeSubmenu: aSubmenu [ 13 | "This is where submenus get automagically updated" 14 | (aSubmenu notNil and: [ aSubmenu respondsTo: #updateMenu]) ifTrue: [aSubmenu updateMenu]. 15 | super activeSubmenu: aSubmenu. 16 | ] 17 | 18 | { #category : #accessing } 19 | TWMDockingBarMorph >> icons [ 20 | ^Smalltalk ui icons 21 | ] 22 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMUpdatingMenuMorph.class.st: -------------------------------------------------------------------------------- 1 | " 2 | A menu updating itself 3 | " 4 | Class { 5 | #name : #TWMUpdatingMenuMorph, 6 | #superclass : #DockingBarMenuMorph, 7 | #instVars : [ 8 | 'updater', 9 | 'updateSelector' 10 | ], 11 | #category : 'TWM-GUI' 12 | } 13 | 14 | { #category : #update } 15 | TWMUpdatingMenuMorph >> updateMenu [ 16 | "Reconstitute the menu by first removing the contents and then building it afresh" 17 | self flag: #TODO. "Reinstate this feature once we figure out why it crashes" 18 | 19 | self removeAllMorphs. 20 | updater perform: updateSelector with: self 21 | 22 | 23 | ] 24 | 25 | { #category : #initialization } 26 | TWMUpdatingMenuMorph >> updater: anObject updateSelector: aSelector [ 27 | "Set the receiver's updater and updateSelector" 28 | 29 | updater := anObject. 30 | updateSelector := aSelector 31 | ] 32 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMLayoutStrategy.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm the base class for defining strategies to tile / place windows. 3 | 4 | Just implement #tileWindows: 5 | " 6 | Class { 7 | #name : #TWMLayoutStrategy, 8 | #superclass : #Object, 9 | #instVars : [ 10 | 'world' 11 | ], 12 | #category : 'TWM-Core' 13 | } 14 | 15 | { #category : #layout } 16 | TWMLayoutStrategy >> tileWindow: window bounds: bounds [ 17 | window isMaximized ifTrue: [window expandBoxHit]. 18 | window 19 | expandAndActivate; 20 | bounds: bounds. 21 | 22 | ] 23 | 24 | { #category : #layout } 25 | TWMLayoutStrategy >> tileWindows: windows [ 26 | self subclassResponsibility 27 | ] 28 | 29 | { #category : #accessing } 30 | TWMLayoutStrategy >> world [ 31 | ^ world 32 | ] 33 | 34 | { #category : #accessing } 35 | TWMLayoutStrategy >> world: anObject [ 36 | world := anObject 37 | ] 38 | -------------------------------------------------------------------------------- /packages/BaselineOfTilingWindowManager/BaselineOfTilingWindowManager.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I am a baseline of TilingWindowManager, read more at: https://github.com/pharophile/TilingWindowManager 3 | " 4 | Class { 5 | #name : #BaselineOfTilingWindowManager, 6 | #superclass : #BaselineOf, 7 | #category : 'BaselineOfTilingWindowManager' 8 | } 9 | 10 | { #category : #baseline } 11 | BaselineOfTilingWindowManager >> baseline: spec [ 12 | 13 | 14 | spec for: #common do: [ 15 | spec blessing: #baseline. 16 | spec 17 | package: 'TWM-Core'; 18 | package: 'TWM-GUI' with: [spec requires: 'TWM-Core']; 19 | package: 'TWM-KeyMapping' with: [spec requires: 'TWM-GUI']; 20 | package: 'TWM-Tests' with: [spec requires: #('TWM-GUI' 'TWM-KeyMapping')]; 21 | package: 'TWM-Theme'; 22 | postLoadDoIt: #openTWMBar. 23 | 24 | spec 25 | group: 'default' with: #('ALL'); 26 | group: 'core' with: #('TWM-GUI') 27 | ] 28 | ] 29 | 30 | { #category : #'pre-post-load-do-its' } 31 | BaselineOfTilingWindowManager >> openTWMBar [ 32 | TWMBar open 33 | ] 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 Philippe Back 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /packages/TWM-Theme/StandardTabPanelBorder.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #StandardTabPanelBorder, 3 | #superclass : #TabPanelBorder, 4 | #category : 'TWM-Theme' 5 | } 6 | 7 | { #category : #drawing } 8 | StandardTabPanelBorder >> frameRectangle: aRectangle on: aCanvas [ 9 | "Draw the border taking the currently selected tab into account. 10 | Only works for top-positioned tabs for the moment." 11 | 12 | |w h r tab| 13 | w := self width. 14 | w isPoint ifTrue: [h := w y. w := w x] ifFalse:[h := w]. 15 | tab := self selectedTab. 16 | tab ifNil: [ 17 | r := aRectangle topLeft + (w@0) corner: aRectangle topRight - (w@h negated). 18 | aCanvas fillRectangle: r color: self color. 19 | ^self]. "top" 20 | r := aRectangle topLeft + (w@0) corner: tab bounds left + w@(aRectangle top + h). 21 | aCanvas fillRectangle: r color: self color. "top 1" 22 | r := tab bounds left + w@ aRectangle top corner: tab bounds right - w@(aRectangle top + h). 23 | aCanvas fillRectangle: r color: tab paneColor. "top 2" 24 | r := tab bounds right - w@ aRectangle top corner: aRectangle topRight - (w@h negated). 25 | aCanvas fillRectangle: r color: self color. "top 3" 26 | ] 27 | -------------------------------------------------------------------------------- /packages/TWM-Core/PasteUpMorph.extension.st: -------------------------------------------------------------------------------- 1 | Extension { #name : #PasteUpMorph } 2 | 3 | { #category : #'*twm-core' } 4 | PasteUpMorph class >> defaultWorldColor [ 5 | ^ Color white. 6 | 7 | ] 8 | 9 | { #category : #'*twm-core' } 10 | PasteUpMorph >> initAsTestWorld: aWorldState [ 11 | worldState := aWorldState. 12 | bounds := Display boundingBox. 13 | self viewBox: bounds. 14 | ] 15 | 16 | { #category : #'*twm-core' } 17 | PasteUpMorph >> initAsWorld: aWorldState [ 18 | worldState := aWorldState. 19 | bounds := Display boundingBox. 20 | self color: self defaultWorldColor. 21 | self addHand: HandMorph new. 22 | self setProperty: #optimumExtentFromAuthor toValue: Display extent. 23 | self borderWidth: 0. 24 | "model := nil." "This doesn't exists in PasteUpMorph anymore." 25 | ] 26 | 27 | { #category : #'*twm-core' } 28 | PasteUpMorph class >> newWorld [ 29 | 30 | ^ self new initAsWorld: WorldState new 31 | ] 32 | 33 | { #category : #'*twm-core' } 34 | PasteUpMorph >> prepareToDeactivate [ 35 | "Some things still may need to be brought from Squeak: 36 | * MorphicProject>>pauseSoundPlayers" 37 | 38 | self 39 | triggerEvent: #aboutToLeaveWorld; 40 | sleep. 41 | 42 | Sensor 43 | flushNonKbdEvents; 44 | flushKeyboard. 45 | ] 46 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWithNoWindowsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMWithNoWindowsTest, 3 | #superclass : #WMInANewWorldTestCase, 4 | #category : 'TWM-Tests' 5 | } 6 | 7 | { #category : #'tests-keymapping-settings' } 8 | WMWithNoWindowsTest >> testKeymappingRepositoryShourdIncludeCategoryNamedtwmShortcuts [ 9 | self assert: (KMRepository default includesCategoryNamed: #twmShortcuts) 10 | ] 11 | 12 | { #category : #'tests-keymapping-settings' } 13 | WMWithNoWindowsTest >> testKeymappingSettingsShourdIncludeShortcutToTileVisibleWindows [ 14 | | builder | 15 | builder := SettingTreeBuilder new. 16 | TWMKeymapping buildSettingsOn: builder. 17 | builder nodeList detect: [:aNode| aNode item name = #tileVisibleWindows]. 18 | ] 19 | 20 | { #category : #'tests-tiling' } 21 | WMWithNoWindowsTest >> testTileLastUsedWindowsShouldNotRaiseError [ 22 | self shouldnt: [windowManager tileLastUsedWindows] raise: Error. 23 | ] 24 | 25 | { #category : #'tests-tiling' } 26 | WMWithNoWindowsTest >> testTileVisibleWindowsShouldNotRaiseError [ 27 | self shouldnt: [windowManager tileVisibleWindows ] raise: Error. 28 | ] 29 | 30 | { #category : #'tests-tiling' } 31 | WMWithNoWindowsTest >> testWindowManagerWorldShouldReturnTestWorld [ 32 | self assert: testWorld equals: windowManager world. 33 | ] 34 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMBarButtonBuilder.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I build a button for TWMBar. 3 | 4 | You can declare your own custom buttons to be added in the TWMBar using the pragma . Just define a class side method like this: 5 | 6 | buttonTestRunner: aBuilder 7 | 8 | aBuilder 9 | action: [TestRunner open]; 10 | help: 'test open TestRunner'; 11 | icon: TestRunner taskbarIcon'. 12 | " 13 | Class { 14 | #name : #TWMBarButtonBuilder, 15 | #superclass : #Object, 16 | #instVars : [ 17 | 'button', 18 | 'priority' 19 | ], 20 | #category : 'TWM-GUI' 21 | } 22 | 23 | { #category : #accessing } 24 | TWMBarButtonBuilder >> action: aBlock [ 25 | self button 26 | target: aBlock; 27 | actionSelector: #value. 28 | ] 29 | 30 | { #category : #accessing } 31 | TWMBarButtonBuilder >> button [ 32 | ^ button ifNil: [button := IconicButton new color: Color transparent]. 33 | ] 34 | 35 | { #category : #accessing } 36 | TWMBarButtonBuilder >> help: aString [ 37 | self button setBalloonText: aString 38 | ] 39 | 40 | { #category : #accessing } 41 | TWMBarButtonBuilder >> icon: aForm [ 42 | self button labelGraphic: aForm 43 | ] 44 | 45 | { #category : #accessing } 46 | TWMBarButtonBuilder >> priority [ 47 | ^ priority ifNil: [priority := 0]. 48 | ] 49 | 50 | { #category : #accessing } 51 | TWMBarButtonBuilder >> priority: aSmallInteger [ 52 | priority := aSmallInteger 53 | ] 54 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWithAnOBBrowserAndDockingBarsTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMWithAnOBBrowserAndDockingBarsTest, 3 | #superclass : #WMInANewWorldTestCase, 4 | #instVars : [ 5 | 'taskBar', 6 | 'obbrowser', 7 | 'leftBar' 8 | ], 9 | #category : 'TWM-Tests' 10 | } 11 | 12 | { #category : #testing } 13 | WMWithAnOBBrowserAndDockingBarsTest >> expectedFailures [ 14 | ^ (Smalltalk at: #OBSystemBrowser ifAbsent: nil) 15 | ifNil: [self class testSelectors] 16 | ifNotNil: [#()] 17 | ] 18 | 19 | { #category : #running } 20 | WMWithAnOBBrowserAndDockingBarsTest >> setUp [ 21 | super setUp. 22 | 23 | obbrowser := self newWindowFor: #OBSystemBrowser. 24 | 25 | taskBar := TaskbarMorph new 26 | openInWorld: testWorld; 27 | adhereToEdge: #bottom. 28 | 29 | leftBar := DockingBarMorph new 30 | adhereToLeft; 31 | width: 25; 32 | openInWorld: testWorld. 33 | ] 34 | 35 | { #category : #tests } 36 | WMWithAnOBBrowserAndDockingBarsTest >> testBrowsersShouldReturnOBBrowser [ 37 | self assert: {obbrowser} equals: windowManager browsers 38 | ] 39 | 40 | { #category : #tests } 41 | WMWithAnOBBrowserAndDockingBarsTest >> testTaskbarHeightShouldBeMoreThanZero [ 42 | self assert: (taskBar height > 0) 43 | ] 44 | 45 | { #category : #tests } 46 | WMWithAnOBBrowserAndDockingBarsTest >> testTileVisibleWindowsShouldNotCoverDockedBar [ 47 | windowManager tileVisibleWindows. 48 | self assert: ((leftBar width)@0 extent: (200 - leftBar width)@(200 - taskBar height)) equals: obbrowser bounds. 49 | ] 50 | -------------------------------------------------------------------------------- /packages/TWM-Tests/TWMTestHelpers.trait.st: -------------------------------------------------------------------------------- 1 | " 2 | I define useful method to search submorphs of TWMBar for testing 3 | " 4 | Trait { 5 | #name : #TWMTestHelpers, 6 | #category : 'TWM-Tests' 7 | } 8 | 9 | { #category : #assertions } 10 | TWMTestHelpers >> assertMenuWithIcon: aForm containsItemNamed: aString [ 11 | self deny: (self itemNamed: aString fromMenuWithIcon: aForm) isNil. 12 | ] 13 | 14 | { #category : #finders } 15 | TWMTestHelpers >> iconicButtonWithTarget: aBlock [ 16 | ^ self twmBar dock 17 | findDeepSubmorphThat: [ :aMorph | 18 | (aMorph isKindOf: IconicButton) 19 | and: [ aMorph target asString = aBlock asString and: [ aMorph actionSelector = #value ] ] ] 20 | ifAbsent: [ nil ] 21 | ] 22 | 23 | { #category : #finders } 24 | TWMTestHelpers >> itemNamed:aString fromMenu: aMenu [ 25 | self twmBar dock activeSubmenu: aMenu subMenu. 26 | ^ aMenu subMenu allMorphs detect: [:aMorph| (aMorph isKindOf: MenuItemMorph) 27 | and:[aMorph contents = aString]]. 28 | 29 | ] 30 | 31 | { #category : #finders } 32 | TWMTestHelpers >> itemNamed:aString fromMenuWithIcon: aForm [ 33 | ^ self itemNamed: aString fromMenu: (self menuWithIcon: aForm). 34 | ] 35 | 36 | { #category : #finders } 37 | TWMTestHelpers >> menuWithIcon: aForm [ 38 | ^ self twmBar dock 39 | findDeepSubmorphThat: [:aMorph| 40 | (aMorph isKindOf: MenuItemMorph) and:[aMorph icon = aForm]] 41 | ifAbsent: [nil]. 42 | ] 43 | 44 | { #category : #requirements } 45 | TWMTestHelpers >> twmBar [ 46 | self explicitRequirement 47 | ] 48 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWhenTopWindowIsNilTestCase.class.st: -------------------------------------------------------------------------------- 1 | " 2 | To test window manager when top window is nil. 3 | " 4 | Class { 5 | #name : #WMWhenTopWindowIsNilTestCase, 6 | #superclass : #WMInANewWorldTestCase, 7 | #category : 'TWM-Tests' 8 | } 9 | 10 | { #category : #running } 11 | WMWhenTopWindowIsNilTestCase >> setUp [ 12 | super setUp. 13 | SystemWindow passivateTopWindow 14 | ] 15 | 16 | { #category : #'move tests' } 17 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveBottom [ 18 | windowManager topWindowMoveBottom. 19 | 20 | ] 21 | 22 | { #category : #'move tests' } 23 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveBottomLeft [ 24 | windowManager topWindowMoveBottomLeft. 25 | 26 | ] 27 | 28 | { #category : #'move tests' } 29 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveBottomRight [ 30 | windowManager topWindowMoveBottomRight. 31 | 32 | ] 33 | 34 | { #category : #'move tests' } 35 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveLeft [ 36 | windowManager topWindowMoveLeft. 37 | 38 | ] 39 | 40 | { #category : #'move tests' } 41 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveRight [ 42 | windowManager topWindowMoveRight. 43 | 44 | ] 45 | 46 | { #category : #'move tests' } 47 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveTop [ 48 | windowManager topWindowMoveTop. 49 | 50 | ] 51 | 52 | { #category : #'move tests' } 53 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveTopLeft [ 54 | windowManager topWindowMoveTopLeft. 55 | 56 | ] 57 | 58 | { #category : #'move tests' } 59 | WMWhenTopWindowIsNilTestCase >> testTopWindowMoveTopRight [ 60 | windowManager topWindowMoveTopRight. 61 | 62 | ] 63 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMVerticalLayoutStrategy.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I place the windows in a grid, by row and column, in the order of last used window (last used first). Top left window fill all vertical space left. 3 | " 4 | Class { 5 | #name : #TWMVerticalLayoutStrategy, 6 | #superclass : #TWMLayoutStrategy, 7 | #category : 'TWM-Core' 8 | } 9 | 10 | { #category : #accessing } 11 | TWMVerticalLayoutStrategy class >> strategyName [ 12 | ^ 'Vertical layout' translated 13 | ] 14 | 15 | { #category : #layout } 16 | TWMVerticalLayoutStrategy >> tileWindows: windows [ 17 | | windowsToPlace numberOfColumns numberOfRows windowWidth windowHeight clearArea origin | 18 | windowsToPlace := OrderedCollection newFrom: windows. 19 | clearArea := world clearArea. 20 | origin := clearArea bottomRight. 21 | 22 | numberOfRows := 1 max: ((windowsToPlace size + 1) sqrtFloor). 23 | numberOfColumns := 1 max: ((windowsToPlace size / numberOfRows) rounded). 24 | windowWidth := clearArea width // numberOfColumns.. 25 | windowHeight := clearArea height // numberOfRows. 26 | 27 | Matrix 28 | rows: numberOfColumns 29 | columns: numberOfRows 30 | tabulate: [:column :row| 31 | windowsToPlace ifNotEmpty: [ |window topLeft effectiveHeight| 32 | window := windowsToPlace remove: windowsToPlace last. 33 | windowsToPlace isEmpty 34 | ifTrue: [ topLeft := clearArea topLeft. 35 | effectiveHeight := windowHeight * (numberOfRows - row + 1)] 36 | ifFalse: [topLeft := origin - ((column * windowWidth) @ (row * windowHeight)). 37 | effectiveHeight := windowHeight]. 38 | self tileWindow: window bounds: (topLeft extent: windowWidth@effectiveHeight) 39 | ] 40 | ] 41 | ] 42 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMHorizontalLayoutStrategy.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I place the windows in a grid, by column and row, in the order of last used window (last used first). Top left window fill all horizontal space left. 3 | " 4 | Class { 5 | #name : #TWMHorizontalLayoutStrategy, 6 | #superclass : #TWMLayoutStrategy, 7 | #category : 'TWM-Core' 8 | } 9 | 10 | { #category : #accessing } 11 | TWMHorizontalLayoutStrategy class >> strategyName [ 12 | ^ 'Horizontal Layout' translated 13 | ] 14 | 15 | { #category : #layout } 16 | TWMHorizontalLayoutStrategy >> tileWindows: windows [ 17 | | windowsToPlace numberOfColumns numberOfRows windowWidth windowHeight clearArea origin | 18 | windowsToPlace := OrderedCollection newFrom: windows. 19 | clearArea := world clearArea. 20 | origin := clearArea bottomRight. 21 | 22 | numberOfColumns := 1 max: ((windowsToPlace size + 1) sqrtFloor). 23 | numberOfRows := 1 max: ((windowsToPlace size / numberOfColumns) rounded). 24 | windowWidth := clearArea width // numberOfColumns.. 25 | windowHeight := clearArea height // numberOfRows. 26 | 27 | Matrix 28 | rows: numberOfRows 29 | columns: numberOfColumns 30 | tabulate: [:row :column| 31 | windowsToPlace ifNotEmpty: [ |window topLeft effectiveWidth| 32 | window := windowsToPlace remove: windowsToPlace last. 33 | windowsToPlace isEmpty 34 | ifTrue: [ topLeft := clearArea topLeft. 35 | effectiveWidth := windowWidth * (numberOfColumns - column + 1)] 36 | ifFalse: [topLeft := origin - ((column * windowWidth) @ (row * windowHeight)). 37 | effectiveWidth := windowWidth]. 38 | self tileWindow: window bounds: (topLeft extent: effectiveWidth@windowHeight) 39 | ] 40 | ] 41 | ] 42 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMInANewWorldTestCase.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMInANewWorldTestCase, 3 | #superclass : #TestCase, 4 | #instVars : [ 5 | 'testWorld', 6 | 'windowManager', 7 | 'backupLayoutStrategy' 8 | ], 9 | #category : 'TWM-Tests' 10 | } 11 | 12 | { #category : #testing } 13 | WMInANewWorldTestCase class >> isAbstract [ 14 | ^ self = WMInANewWorldTestCase 15 | ] 16 | 17 | { #category : #factory } 18 | WMInANewWorldTestCase >> newBrowserIn: aWorld [ 19 | ^ SystemWindow new 20 | model: Browser new; 21 | openInWorld: testWorld; 22 | yourself. 23 | ] 24 | 25 | { #category : #factory } 26 | WMInANewWorldTestCase >> newWindowFor: aClassName [ 27 | ^ self newWindowForModelClass: (Smalltalk at: aClassName). 28 | ] 29 | 30 | { #category : #factory } 31 | WMInANewWorldTestCase >> newWindowForModelClass: aClass [ 32 | ^ SystemWindow new 33 | model: aClass new; 34 | openInWorld: testWorld; 35 | yourself. 36 | ] 37 | 38 | { #category : #factory } 39 | WMInANewWorldTestCase >> newWorkspaceIn: aWorld [ 40 | | workspace | 41 | workspace := SystemWindow new 42 | model: Workspace new; 43 | openInWorld: testWorld; 44 | yourself. 45 | 46 | workspace addMorph: workspace model buildTextMorph. 47 | ^ workspace 48 | ] 49 | 50 | { #category : #running } 51 | WMInANewWorldTestCase >> setUp [ 52 | testWorld := WorldMorph new 53 | initAsTestWorld: WorldState new; 54 | yourself. 55 | testWorld bounds: (0@0 extent: 200@200). 56 | windowManager := TilingWM forWorld: testWorld. 57 | 58 | backupLayoutStrategy := TilingWM layoutStrategyClassName. 59 | TilingWM layoutStrategyClassName: #TWMHorizontalLayoutStrategy. 60 | ] 61 | 62 | { #category : #running } 63 | WMInANewWorldTestCase >> tearDown [ 64 | TilingWM layoutStrategyClassName: backupLayoutStrategy 65 | 66 | ] 67 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMWorldSnapshot.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I remember the state of all the windows opened in a World and I'm able to restore it later. 3 | " 4 | Class { 5 | #name : #TWMWorldSnapshot, 6 | #superclass : #Object, 7 | #instVars : [ 8 | 'world', 9 | 'windowSnapshots', 10 | 'thumbnail' 11 | ], 12 | #category : 'TWM-Core' 13 | } 14 | 15 | { #category : #'initialize-release' } 16 | TWMWorldSnapshot class >> of: aWorld [ 17 | ^ self new snapshot: aWorld. 18 | ] 19 | 20 | { #category : #equality } 21 | TWMWorldSnapshot >> = anObject [ 22 | ^ self windowSnapshots = anObject windowSnapshots. 23 | ] 24 | 25 | { #category : #equality } 26 | TWMWorldSnapshot >> hash [ 27 | ^ super hash bitXor: windowSnapshots hash. 28 | ] 29 | 30 | { #category : #snapshot } 31 | TWMWorldSnapshot >> restore [ 32 | self windowSnapshots reverse do: [:aSnapshot| aSnapshot restore]. 33 | self snapshot. 34 | ] 35 | 36 | { #category : #snapshot } 37 | TWMWorldSnapshot >> snapshot [ 38 | |worldImage| 39 | windowSnapshots := world systemWindows collect: [:aWindow| TWMWindowSnapshot of: aWindow]. 40 | worldImage := World imageForm. 41 | thumbnail := worldImage magnifyBy: (self thumbnailWidth / worldImage width) asFloat. 42 | ] 43 | 44 | { #category : #snapshot } 45 | TWMWorldSnapshot >> snapshot: aWorld [ 46 | world := aWorld. 47 | self snapshot. 48 | ] 49 | 50 | { #category : #accessing } 51 | TWMWorldSnapshot >> thumbnail [ 52 | ^ thumbnail ifNil: [Form new] 53 | ] 54 | 55 | { #category : #accessing } 56 | TWMWorldSnapshot >> thumbnailWidth [ 57 | ^ 200 58 | ] 59 | 60 | { #category : #accessing } 61 | TWMWorldSnapshot >> visibleWindows [ 62 | ^ self windows reject: [:aWindow| aWindow isMinimized] 63 | ] 64 | 65 | { #category : #accessing } 66 | TWMWorldSnapshot >> windowSnapshots [ 67 | ^ (windowSnapshots ifNil: [windowSnapshots := {}]) 68 | reject: [:aSnapshot| aSnapshot window owner isNil]. 69 | 70 | ] 71 | 72 | { #category : #accessing } 73 | TWMWorldSnapshot >> windows [ 74 | ^ self windowSnapshots collect: [:aWindowSnapshot| aWindowSnapshot window]. 75 | ] 76 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMSettings.class.st: -------------------------------------------------------------------------------- 1 | " 2 | System Settings for Tiling Window Manager 3 | " 4 | Class { 5 | #name : #TWMSettings, 6 | #superclass : #Object, 7 | #category : 'TWM-GUI' 8 | } 9 | 10 | { #category : #settings } 11 | TWMSettings class >> displayEnableTWMSettingsOn: aBuilder [ 12 | 13 | (aBuilder setting: #showTWMBar) 14 | label: 'Enable Tiling Window Manager' translated; 15 | target: TWMBar; 16 | parent: #twm; 17 | description: 'Open a dock with TWM actions' translated; 18 | order: 1 19 | 20 | ] 21 | 22 | { #category : #settings } 23 | TWMSettings class >> displayLayoutStrategySettingsOn: aBuilder [ 24 | 25 | (aBuilder pickOne: #layoutStrategyClassName) 26 | label: 'Layout strategy' translated; 27 | target: TilingWM; 28 | parent: #twm; 29 | order: 2; 30 | description: 'Layout strategy to tile windows' translated; 31 | default: #TWMHorizontalLayoutStrategy; 32 | domainValues: (TWMLayoutStrategy subclasses collect: [:aClass| (aClass strategyName) -> aClass name]). 33 | ] 34 | 35 | { #category : #settings } 36 | TWMSettings class >> displayNumberOfLastUsedWindowsSettingsOn: aBuilder [ 37 | 38 | (aBuilder setting: #numberOfLastUsedWindows) 39 | label: 'Last used windows to show' translated; 40 | target: TilingWM; 41 | parent: #twm; 42 | order: 3; 43 | description: 'Number of last used windows to show' translated. 44 | 45 | ] 46 | 47 | { #category : #settings } 48 | TWMSettings class >> displayTWMBarSettingsOn: aBuilder [ 49 | 50 | (aBuilder group: #twm) 51 | label: 'Tiling Window Manager' translated; 52 | description: 'TWM allows to put windows side by side automatically' translated. 53 | ] 54 | 55 | { #category : #'initialize-release' } 56 | TWMSettings class >> initialize [ 57 | self reloadTWMBar. 58 | ] 59 | 60 | { #category : #reloading } 61 | TWMSettings class >> reloadTWMBar [ 62 | self flag: #TODO. "If there are multiple worlds, this is flawed." 63 | TWMBar showTWMBar ifTrue: [TWMBar default rebuildDockContent]. 64 | ] 65 | 66 | { #category : #accessing } 67 | TWMSettings class >> windowManager [ 68 | ^ TilingWM instanceForCurrentWorld 69 | ] 70 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMWindowSnapshot.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I remember the state of a SystemWindow (bounds, minimized / maximized) and I'm able to restore it later. 3 | " 4 | Class { 5 | #name : #TWMWindowSnapshot, 6 | #superclass : #Object, 7 | #instVars : [ 8 | 'window', 9 | 'bounds', 10 | 'shouldRestoreMinimized', 11 | 'shouldRestoreMaximized' 12 | ], 13 | #category : 'TWM-Core' 14 | } 15 | 16 | { #category : #'initialize-release' } 17 | TWMWindowSnapshot class >> of: aSystemWindow [ 18 | ^ self new snapshot: aSystemWindow 19 | ] 20 | 21 | { #category : #equality } 22 | TWMWindowSnapshot >> = anObject [ 23 | ^ (anObject isKindOf: self class) 24 | and: [anObject window = self window 25 | and: [anObject bounds = self bounds 26 | and: [anObject shouldRestoreMinimized = anObject shouldRestoreMinimized 27 | and: [anObject shouldRestoreMaximized = anObject shouldRestoreMaximized ]]]]. 28 | ] 29 | 30 | { #category : #accessing } 31 | TWMWindowSnapshot >> bounds [ 32 | ^ bounds 33 | ] 34 | 35 | { #category : #equality } 36 | TWMWindowSnapshot >> hash [ 37 | ^ (((super hash 38 | bitXor: self bounds hash) 39 | bitXor: (self window hash)) 40 | bitXor: self shouldRestoreMaximized hash) 41 | bitXor: self shouldRestoreMinimized hash. 42 | ] 43 | 44 | { #category : #snapshot } 45 | TWMWindowSnapshot >> restore [ 46 | (shouldRestoreMinimized not & window isMinimized) ifTrue: [window expandBoxHit]. 47 | (shouldRestoreMaximized not &window isMaximized) ifTrue: [window expandBoxHit]. 48 | 49 | shouldRestoreMaximized ifTrue: [window maximize]. 50 | shouldRestoreMinimized ifTrue: [window minimize]. 51 | 52 | window 53 | bounds: bounds; 54 | activate. 55 | ] 56 | 57 | { #category : #accessing } 58 | TWMWindowSnapshot >> shouldRestoreMaximized [ 59 | ^ shouldRestoreMaximized 60 | ] 61 | 62 | { #category : #accessing } 63 | TWMWindowSnapshot >> shouldRestoreMinimized [ 64 | ^ shouldRestoreMinimized 65 | ] 66 | 67 | { #category : #snapshot } 68 | TWMWindowSnapshot >> snapshot: aSystemWindow [ 69 | window := aSystemWindow. 70 | bounds := window bounds. 71 | shouldRestoreMinimized := window isMinimized. 72 | shouldRestoreMaximized := window isMaximized. 73 | ] 74 | 75 | { #category : #accessing } 76 | TWMWindowSnapshot >> window [ 77 | ^ window 78 | ] 79 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest, 3 | #superclass : #WMWithTwoBrowsersAndTwoWorkspacesTest, 4 | #instVars : [ 5 | 'worldSnapshot' 6 | ], 7 | #category : 'TWM-Tests' 8 | } 9 | 10 | { #category : #running } 11 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> setUp [ 12 | super setUp. 13 | 14 | workspace1 bounds: (10@10 corner: 200@200). 15 | workspace2 bounds: (20@20 corner: 150@150). 16 | browser1 minimize. 17 | browser2 expandBoxHit. 18 | workspace2 activate. 19 | 20 | worldSnapshot := TWMWorldSnapshot of: testWorld. 21 | 22 | windowManager tileVisibleWindows. 23 | browser2 delete. 24 | workspace1 activate. 25 | worldSnapshot restore. 26 | ] 27 | 28 | { #category : #tests } 29 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testBrowserOneShouldBeMinimized [ 30 | self assert: browser1 isMinimized 31 | ] 32 | 33 | { #category : #tests } 34 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testBrowserTwoShouldNotBeVisible [ 35 | self deny: (testWorld systemWindows includes: browser2 ) 36 | ] 37 | 38 | { #category : #tests } 39 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testShouldBeEqualsOtherSnapshotWithoutMoving [ 40 | self assert: worldSnapshot equals: (TWMWorldSnapshot of: testWorld). 41 | ] 42 | 43 | { #category : #tests } 44 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testVisibleWindowsShouldReturnWorkspaceTwoAndOne [ 45 | self assert: {workspace2. workspace1} equals: worldSnapshot visibleWindows. 46 | ] 47 | 48 | { #category : #tests } 49 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testWindowSnapshotForDeletedBrowserTwoShouldBeDiscarded [ 50 | self assert: {workspace2. workspace1. browser1} equals: (worldSnapshot windows) 51 | ] 52 | 53 | { #category : #tests } 54 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testWorkspaceOneBoundsShouldBe10At10Corner200At200 [ 55 | self assert: (10@10 corner: 200@200) equals: workspace1 bounds. 56 | ] 57 | 58 | { #category : #tests } 59 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testWorkspaceTwoBoundsShouldBe20At20Corner150At150 [ 60 | self assert: (20@20 corner: 150@150) equals: workspace2 bounds. 61 | ] 62 | 63 | { #category : #tests } 64 | WMWithTwoBrowsersAndTwoWorkspacesAfterWorldSnapshotTest >> testWorkspaceTwoShouldBeOnTop [ 65 | self assert: workspace2 equals: workspace2 topWindow. 66 | ] 67 | -------------------------------------------------------------------------------- /packages/ConfigurationOfTilingWindowManager/ConfigurationOfTilingWindowManager.class.st: -------------------------------------------------------------------------------- 1 | " 2 | Tiling Window Manager is a set of tools to organize windows on you Pharo desktop. 3 | 4 | Load with: 5 | ConfigurationOfTilingWindowManager load. 6 | (or see class side, protocol loading for alternate ways). 7 | 8 | Then: 9 | TWMBar open. 10 | (or browse settings for Tiling Window Manager). 11 | 12 | 13 | If you want a more customized setup, try: 14 | 15 | (Smalltalk at:#TWMUITheme) beCurrent. 16 | TaskbarMorph showTaskbar: false. 17 | TasklistMorph keepOpen: true. 18 | (Smalltalk at:#TWMBar) perform: #showTWMBar: with: true. 19 | " 20 | Class { 21 | #name : #ConfigurationOfTilingWindowManager, 22 | #superclass : #ConfigurationOf, 23 | #category : 'ConfigurationOfTilingWindowManager' 24 | } 25 | 26 | { #category : #catalog } 27 | ConfigurationOfTilingWindowManager class >> catalogChangeLog [ 28 | ^ 'Version 5.0.2 - Make TWM work in Pharo5' 29 | ] 30 | 31 | { #category : #catalog } 32 | ConfigurationOfTilingWindowManager class >> catalogDescription [ 33 | 34 | ^ 35 | 'Tiling Window Manager, multi-desktop IDE. Improves window management and add keyboard shortcuts to handle lot of opened windows.' 36 | ] 37 | 38 | { #category : #catalog } 39 | ConfigurationOfTilingWindowManager class >> catalogKeyClassesAndExample [ 40 | ^ '==TilingWM== is the core class. Try: 41 | [[[ 42 | (TilingWM forWorld: World) tileVisibleWindows. 43 | (TilingWM forWorld: World) tileBrowsers. 44 | (TilingWM forWorld: World) tileWorkspaces. 45 | ]]] 46 | 47 | ==TWMWorldManager== manages multiple desktops: 48 | 49 | Add a world: 50 | [[[ 51 | WorldManager instance createOrSwitchToWorldNamed: ''JustAnotherWorld''. 52 | ]]] 53 | 54 | Return to the default world: 55 | [[[ 56 | WorldManager instance createOrSwitchToWorldNamed: ''Pharo''. 57 | ]]] 58 | 59 | 60 | ==TWMLayoutStrategy== subclasses provide several layout strategies. Implement your own ! 61 | 62 | ==TWMBar== handles the GUI part of TWM. 63 | [[[ 64 | TWMBar new open 65 | ]]] 66 | 67 | '. 68 | ] 69 | 70 | { #category : #catalog } 71 | ConfigurationOfTilingWindowManager class >> catalogKeywords [ 72 | ^ #(IDE) 73 | 74 | ] 75 | 76 | { #category : #versions } 77 | ConfigurationOfTilingWindowManager >> version504: spec [ 78 | 79 | 80 | spec for: #common do: [ 81 | spec blessing: #development. 82 | spec author: 'Philippe Back'. 83 | spec description: 'TWM in Pharo 5.x'. 84 | spec timestamp: '10/31/2016 21:13'. 85 | spec baseline: 'TilingWindowManager' with: [ 86 | spec repository: 'github://pharophile/TilingWindowManager:master/packages' ]; 87 | import: 'ALL' 88 | ]. 89 | 90 | 91 | ] 92 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMWorldRecorder.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I create and store snapshots of the world, so you can go back and forth between different windows / world contexts 3 | " 4 | Class { 5 | #name : #TWMWorldRecorder, 6 | #superclass : #Object, 7 | #instVars : [ 8 | 'world', 9 | 'snapshots', 10 | 'currentPosition' 11 | ], 12 | #classInstVars : [ 13 | 'world' 14 | ], 15 | #category : 'TWM-Core' 16 | } 17 | 18 | { #category : #'initialize-release' } 19 | TWMWorldRecorder class >> of: aWorld [ 20 | ^ self new world: aWorld 21 | ] 22 | 23 | { #category : #navigate } 24 | TWMWorldRecorder >> backward [ 25 | | currentWorld | 26 | currentWorld := (TWMWorldSnapshot of: world). 27 | (self snapshots includes: currentWorld) 28 | ifFalse: [self snapshots add: currentWorld. 29 | self currentPosition: self currentPosition + 1]. 30 | self currentPosition: self currentPosition - 1. 31 | self restoreCurrentSnapshot. 32 | ] 33 | 34 | { #category : #accessing } 35 | TWMWorldRecorder >> currentPosition [ 36 | ^ currentPosition ifNil: [currentPosition := 1] 37 | ] 38 | 39 | { #category : #accessing } 40 | TWMWorldRecorder >> currentPosition: anInteger [ 41 | anInteger > 0 ifTrue: [currentPosition := (anInteger min: self snapshots size)]. 42 | ] 43 | 44 | { #category : #accessing } 45 | TWMWorldRecorder >> currentSnapshot [ 46 | ^ self snapshots at: (self currentPosition) 47 | ] 48 | 49 | { #category : #snapshot } 50 | TWMWorldRecorder >> deleteCurrentSnapshot [ 51 | (self snapshots size = 1) not ifTrue: [ 52 | self snapshots remove: self currentSnapshot. 53 | self currentPosition: self currentPosition - 1. 54 | ] 55 | ] 56 | 57 | { #category : #navigate } 58 | TWMWorldRecorder >> forward [ 59 | self isAtLast ifFalse: [ 60 | self currentPosition: self currentPosition + 1. 61 | self restoreCurrentSnapshot. 62 | ] 63 | ] 64 | 65 | { #category : #testing } 66 | TWMWorldRecorder >> isAtLast [ 67 | ^ self currentPosition = self snapshots size. 68 | ] 69 | 70 | { #category : #printing } 71 | TWMWorldRecorder >> printPositionOn: aStream [ 72 | aStream nextPutAll: self currentPosition asString, '/', self snapshots size asString. 73 | ] 74 | 75 | { #category : #snapshot } 76 | TWMWorldRecorder >> restoreCurrentSnapshot [ 77 | self currentSnapshot restore. 78 | ] 79 | 80 | { #category : #snapshot } 81 | TWMWorldRecorder >> snapshot [ 82 | self snapshots add: (TWMWorldSnapshot of: world). 83 | self currentPosition: self snapshots size. 84 | ] 85 | 86 | { #category : #accessing } 87 | TWMWorldRecorder >> snapshots [ 88 | ^ snapshots ifNil: [snapshots := OrderedCollection new] 89 | ] 90 | 91 | { #category : #accessing } 92 | TWMWorldRecorder >> world: aPasteUpMorph [ 93 | world := aPasteUpMorph. 94 | self snapshot. 95 | ] 96 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMWorldSnapshotBrowser.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I open a window used to browse and restore world snapshots 3 | " 4 | Class { 5 | #name : #TWMWorldSnapshotBrowser, 6 | #superclass : #Object, 7 | #instVars : [ 8 | 'window', 9 | 'scrollPane' 10 | ], 11 | #category : 'TWM-GUI' 12 | } 13 | 14 | { #category : #accessing } 15 | TWMWorldSnapshotBrowser class >> icons [ 16 | ^Smalltalk ui icons 17 | ] 18 | 19 | { #category : #actions } 20 | TWMWorldSnapshotBrowser class >> open [ 21 | self new open 22 | ] 23 | 24 | { #category : #buttons } 25 | TWMWorldSnapshotBrowser class >> openBrowserButtonOn: aBuilder [ 26 | 27 | aBuilder 28 | action: [self open]; 29 | icon: self icons tinyMenuIcon; 30 | help: 'Browse world snapshots'. 31 | ] 32 | 33 | { #category : #building } 34 | TWMWorldSnapshotBrowser >> buildScrollPaneForSnapshotThumbnails [ 35 | ^ (self builder newScrollPaneFor: self snapshotThumbnailsPanel) 36 | hResizing: #spaceFill; 37 | vResizing: #spaceFill 38 | ] 39 | 40 | { #category : #accessing } 41 | TWMWorldSnapshotBrowser >> builder [ 42 | ^ UITheme builder 43 | ] 44 | 45 | { #category : #callbacks } 46 | TWMWorldSnapshotBrowser >> deleteSnapshot: aTWMWorldSnapshot [ 47 | TilingWM instanceForCurrentWorld worldRecorder snapshots remove: aTWMWorldSnapshot. 48 | window removeMorph: scrollPane. 49 | scrollPane := self buildScrollPaneForSnapshotThumbnails. 50 | window 51 | addMorph: scrollPane fullFrame: (LayoutFrame fractions: (0@0 extent: 1@1) offsets: (0@0 extent: 1@1)). 52 | ] 53 | 54 | { #category : #building } 55 | TWMWorldSnapshotBrowser >> newButtonForWorldSnapshot: aWorldSnapshot [ 56 | ^ self builder 57 | newButtonFor: [ self restoreSnaphot: aWorldSnapshot ] 58 | action: #value 59 | label: (self builder newImage: aWorldSnapshot thumbnail) 60 | help: 'Restore this snapshot' 61 | ] 62 | 63 | { #category : #building } 64 | TWMWorldSnapshotBrowser >> newDeleteButtonForWorldSnapshot: aWorldSnapshot [ 65 | ^ self builder 66 | newButtonFor: [ self deleteSnapshot: aWorldSnapshot ] 67 | action: #value 68 | label: 'Delete' 69 | help: 'Delete this snapshot' 70 | ] 71 | 72 | { #category : #actions } 73 | TWMWorldSnapshotBrowser >> open [ 74 | TilingWM instanceForCurrentWorld snapshotWorld. 75 | scrollPane := self buildScrollPaneForSnapshotThumbnails. 76 | window := scrollPane 77 | extent: 600 @ 400; 78 | openInWindowLabeled: 'Browse snapshots' 79 | ] 80 | 81 | { #category : #callbacks } 82 | TWMWorldSnapshotBrowser >> restoreSnaphot: aTWMWorldSnapshot [ 83 | aTWMWorldSnapshot restore. 84 | window activate. 85 | ] 86 | 87 | { #category : #building } 88 | TWMWorldSnapshotBrowser >> snapshotThumbnailButtons [ 89 | ^ TilingWM currentWorldSnapshots collect: [ :aWorldSnapshot | 90 | self builder newRow: { 91 | self newButtonForWorldSnapshot: aWorldSnapshot. 92 | self newDeleteButtonForWorldSnapshot: aWorldSnapshot } ] 93 | ] 94 | 95 | { #category : #building } 96 | TWMWorldSnapshotBrowser >> snapshotThumbnailsPanel [ 97 | ^ (self builder newColumn: self snapshotThumbnailButtons) 98 | cellPositioning: #topLeft; 99 | hResizing: #shrinkWrap; 100 | vResizing: #shrinkWrap 101 | ] 102 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMDockingWindowMorph.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a dock used to group windows. Open with: 3 | 4 | TWMDockingWindowMorph new openInWorld. 5 | " 6 | Class { 7 | #name : #TWMDockingWindowMorph, 8 | #superclass : #Morph, 9 | #instVars : [ 10 | 'groupWindowMorph' 11 | ], 12 | #classVars : [ 13 | 'Default' 14 | ], 15 | #category : 'TWM-GUI' 16 | } 17 | 18 | { #category : #geometry } 19 | TWMDockingWindowMorph >> defaultExtent [ 20 | ^ 400@300 21 | ] 22 | 23 | { #category : #geometry } 24 | TWMDockingWindowMorph >> edgeToAdhereTo [ 25 | ^ #bottom 26 | ] 27 | 28 | { #category : #initialization } 29 | TWMDockingWindowMorph >> initialize [ 30 | "Initialize the receiver." 31 | super initialize. 32 | 33 | self 34 | initializeAppearance; 35 | initializeGroupWindowMorph; 36 | initializeEdgeGrip. 37 | ] 38 | 39 | { #category : #initialization } 40 | TWMDockingWindowMorph >> initializeAppearance [ 41 | self 42 | changeProportionalLayout; 43 | extent: self defaultExtent; 44 | color: (self theme worldMainDockingBarColorFor: self). 45 | ] 46 | 47 | { #category : #initialization } 48 | TWMDockingWindowMorph >> initializeEdgeGrip [ 49 | |topGrip| 50 | topGrip := EdgeGripMorph new 51 | target: self; 52 | position: self position; 53 | edgeName: #top. 54 | topGrip layoutFrame topOffset: 22. 55 | self addMorph: topGrip. 56 | ] 57 | 58 | { #category : #initialization } 59 | TWMDockingWindowMorph >> initializeGroupWindowMorph [ 60 | groupWindowMorph := GroupWindowMorph new. 61 | groupWindowMorph color: Color black. 62 | self 63 | addMorph: groupWindowMorph 64 | fullFrame: (LayoutFrame fractions: (0@0 corner: 1@1)) 65 | ] 66 | 67 | { #category : #geometry } 68 | TWMDockingWindowMorph >> intoWorld: aWorld [ 69 | "Stick to the bottom left now." 70 | 71 | self 72 | setToAdhereToEdge: #bottomLeft; 73 | updateBounds. 74 | super intoWorld: aWorld 75 | ] 76 | 77 | { #category : #testing } 78 | TWMDockingWindowMorph >> isAdheringToBottom [ 79 | ^ true 80 | ] 81 | 82 | { #category : #testing } 83 | TWMDockingWindowMorph >> isAdheringToLeft [ 84 | ^ false 85 | ] 86 | 87 | { #category : #testing } 88 | TWMDockingWindowMorph >> isAdheringToRight [ 89 | ^ false 90 | ] 91 | 92 | { #category : #testing } 93 | TWMDockingWindowMorph >> isAdheringToTop [ 94 | ^ false 95 | ] 96 | 97 | { #category : #testing } 98 | TWMDockingWindowMorph >> isDockingBar [ 99 | "Answer yes so we get updated when the Display is resized." 100 | 101 | ^true 102 | ] 103 | 104 | { #category : #geometry } 105 | TWMDockingWindowMorph >> minimumExtent [ 106 | ^ 400@50 107 | ] 108 | 109 | { #category : #'event handling' } 110 | TWMDockingWindowMorph >> ownerChanged [ 111 | "The receiver's owner has changed its layout. 112 | Since this method is called synchronously in the 113 | ui, delete the receiver if there are any excpetions." 114 | 115 | self owner ifNil: [^self]. 116 | [self updateBounds] 117 | on: Exception 118 | do: [:ex | self delete. ex pass]. 119 | super ownerChanged 120 | ] 121 | 122 | { #category : #accessing } 123 | TWMDockingWindowMorph >> popUpOwner [ 124 | 125 | ^nil 126 | ] 127 | 128 | { #category : #initialization } 129 | TWMDockingWindowMorph >> updateBounds [ 130 | "Update the receiver's bounds to fill the world." 131 | 132 | self 133 | width: self owner width; 134 | snapToEdgeIfAppropriate. 135 | ] 136 | -------------------------------------------------------------------------------- /packages/TWM-Tests/TWMBarWithTwoBrowsersAndTwoWorkspacesTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #TWMBarWithTwoBrowsersAndTwoWorkspacesTest, 3 | #superclass : #WMWithTwoBrowsersAndTwoWorkspacesTest, 4 | #traits : 'TWMTestHelpers', 5 | #classTraits : 'TWMTestHelpers classTrait', 6 | #instVars : [ 7 | 'twmBar' 8 | ], 9 | #category : 'TWM-Tests' 10 | } 11 | 12 | { #category : #running } 13 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> setUp [ 14 | super setUp. 15 | twmBar := TWMBar new openInWorld: testWorld. 16 | browser1 model setClass: Boolean selector: nil. 17 | browser2 model setClass: String selector: nil. 18 | 19 | workspace2 model contents: 'I am a Workspace with a very long first line. So long, that it would mess up the layout of the TWMBar Menu. So we make sure it gets cut.'. 20 | ] 21 | 22 | { #category : #tests } 23 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testBrowserMenuShouldContainsEntryBooleanForBrowserOne [ 24 | self assertMenuWithIcon: twmBar browsersMenuIcon containsItemNamed: 'Boolean'. 25 | ] 26 | 27 | { #category : #tests } 28 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testBrowserMenuShouldContainsEntryStringForBrowserTwo [ 29 | self assertMenuWithIcon: twmBar browsersMenuIcon containsItemNamed: 'String'. 30 | ] 31 | 32 | { #category : #tests } 33 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testClickOnBrowserTwoMenuItemShouldActivateIt [ 34 | |menuItem| 35 | menuItem := self itemNamed: 'String' fromMenuWithIcon: twmBar browsersMenuIcon. 36 | menuItem target perform: (menuItem selector). 37 | self assert: browser2 equals: SystemWindow topWindow. 38 | ] 39 | 40 | { #category : #tests } 41 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testClickOnBrowserTwoMenuItemWhenHiddenShouldShowIt [ 42 | |menuItem| 43 | browser2 hide. 44 | menuItem := self itemNamed: 'String' fromMenuWithIcon: twmBar browsersMenuIcon. 45 | menuItem target perform: (menuItem selector). 46 | self assert: browser2 equals: SystemWindow topWindow. 47 | self assert: (windowManager visibleWindows includes: browser2). 48 | self assert: browser2 visible. 49 | ] 50 | 51 | { #category : #tests } 52 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testClickOnBrowserTwoMenuItemWhenMinimizedShouldActivateIt [ 53 | |menuItem| 54 | browser2 minimize. 55 | workspace1 activate. 56 | menuItem := self itemNamed: 'String' fromMenuWithIcon: twmBar browsersMenuIcon. 57 | menuItem target perform: (menuItem selector). 58 | self assert: browser2 equals: SystemWindow topWindow. 59 | self assert: (windowManager visibleWindows includes: browser2). 60 | ] 61 | 62 | { #category : #tests } 63 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testOtherToolsMenuShouldContainsEntryForOpeningSUnitTestRunner [ 64 | self assertMenuWithIcon: twmBar otherToolsMenuIcon containsItemNamed: 'New TestRunner'. 65 | ] 66 | 67 | { #category : #tests } 68 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testWindowsMenuShouldContainsEntryStringForBrowserTwo [ 69 | self assertMenuWithIcon: twmBar windowsIcon containsItemNamed: 'String'. 70 | ] 71 | 72 | { #category : #tests } 73 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testWorkspace2MenuShouldContainShortenedStringForWorkspaceThree [ 74 | self assertMenuWithIcon: twmBar workspacesMenuIcon containsItemNamed: 'I am a Workspace with a very long first line. ...'. 75 | ] 76 | 77 | { #category : #tests } 78 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> testWorkspaceMenuShouldContainsEntryStringForWorkspaceOne [ 79 | self assertMenuWithIcon: twmBar workspacesMenuIcon containsItemNamed: '1+1 ...'. 80 | ] 81 | 82 | { #category : #requirements } 83 | TWMBarWithTwoBrowsersAndTwoWorkspacesTest >> twmBar [ 84 | ^ twmBar 85 | ] 86 | -------------------------------------------------------------------------------- /packages/TWM-Core/TWMWorldManager.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I provide an unlimited number of blank canvases on which to create... 3 | 4 | ""Add a world:"" 5 | TWMWorldManager instance createOrSwitchToWorldNamed: 'JustAnotherWorld'. 6 | 7 | ""Return to the default world:"" 8 | TWMWorldManager instance createOrSwitchToWorldNamed: 'Pharo'. 9 | 10 | See http://forum.world.st/Multiple-Worlds-was-Re-Can-I-use-Projects-in-Pharo-td2240869.html for original discussion. 11 | " 12 | Class { 13 | #name : #TWMWorldManager, 14 | #superclass : #Object, 15 | #instVars : [ 16 | 'worlds' 17 | ], 18 | #classVars : [ 19 | 'Instance' 20 | ], 21 | #category : 'TWM-Core' 22 | } 23 | 24 | { #category : #'initialize-release' } 25 | TWMWorldManager class >> instance [ 26 | ^Instance ifNil: [Instance := self new] 27 | ] 28 | 29 | { #category : #'switching worlds' } 30 | TWMWorldManager >> createOrSwitchToWorldNamed: aString [ 31 | self switchToWorld: (self worldNamed: aString ifAbsent: [self newWorldNamed: aString]) 32 | ] 33 | 34 | { #category : #'create / remove worlds' } 35 | TWMWorldManager >> createWorldNamed: aString [ 36 | self switchToWorld: (self newWorldNamed: aString) 37 | ] 38 | 39 | { #category : #accessing } 40 | TWMWorldManager >> currentWorldName [ 41 | ^ worlds keyAtValue: World 42 | ] 43 | 44 | { #category : #'create / remove worlds' } 45 | TWMWorldManager >> deleteCurrentWorld [ 46 | self deleteWorldNamed: (self worlds keyAtValue: World). 47 | ] 48 | 49 | { #category : #'create / remove worlds' } 50 | TWMWorldManager >> deleteWorldNamed: aString [ 51 | | worldToDelete | 52 | (worlds includesKey: aString) 53 | ifFalse: [ ^ self error: 'World named ' , aString , ' does not exists!' ]. 54 | worldToDelete := self worldNamed: aString. 55 | worlds removeKey: aString. 56 | World = worldToDelete ifTrue: [self switchToWorld: worlds values first]. 57 | 58 | ] 59 | 60 | { #category : #initialization } 61 | TWMWorldManager >> initialize [ 62 | super initialize. 63 | worlds := Dictionary new. 64 | ^self 65 | ] 66 | 67 | { #category : #'create / remove worlds' } 68 | TWMWorldManager >> newWorldNamed: aString [ 69 | | newWorld | 70 | (worlds includesKey: aString) 71 | ifTrue: [ ^ self error: 'World named ' , aString , ' already exists!' ]. 72 | newWorld := WorldMorph newWorld. 73 | worlds at: aString put: newWorld. 74 | ^newWorld 75 | 76 | ] 77 | 78 | { #category : #notification } 79 | TWMWorldManager >> notifyWorldChanged [ 80 | 81 | GrowlMorph 82 | openWithLabel: 'World changed' 83 | contents: 'Now in ', self currentWorldName asString 84 | ] 85 | 86 | { #category : #'switching worlds' } 87 | TWMWorldManager >> switchToNextWorld [ 88 | | orderedWorlds currentWorldIndex nextWorld | 89 | self worlds ifNotEmpty: [ 90 | orderedWorlds := self worlds asOrderedCollection. 91 | currentWorldIndex := orderedWorlds indexOf: World. 92 | nextWorld := (orderedWorlds last = World) 93 | ifTrue: [orderedWorlds first] 94 | ifFalse: [orderedWorlds at: (currentWorldIndex + 1)]. 95 | self switchToWorld: nextWorld. 96 | ] 97 | ] 98 | 99 | { #category : #'switching worlds' } 100 | TWMWorldManager >> switchToWorld: newWorld [ 101 | newWorld == World 102 | ifTrue: [ ^ self ]. 103 | self flag: #TODO. "There is something stinky in here, as World isn't the same instance we expect it to be.." 104 | (worlds includes: World) 105 | ifFalse: [ self halt.worlds at: 'XYZ' put: World ]. 106 | World prepareToDeactivate. 107 | newWorld install. 108 | WorldState addDeferredUIMessage: [ 109 | newWorld restoreMorphicDisplay. 110 | self notifyWorldChanged ]. 111 | ] 112 | 113 | { #category : #'switching worlds' } 114 | TWMWorldManager >> switchToWorldNamed: aString [ 115 | self halt. 116 | self switchToWorld: (self worldNamed: aString) 117 | ] 118 | 119 | { #category : #'switching worlds' } 120 | TWMWorldManager >> switchToWorldNamed: aString ifAbsent: aBlock [ 121 | self switchToWorld: (self worldNamed: aString ifAbsent: aBlock) 122 | ] 123 | 124 | { #category : #accessing } 125 | TWMWorldManager >> worldNamed: aString [ 126 | ^worlds at: aString 127 | ] 128 | 129 | { #category : #accessing } 130 | TWMWorldManager >> worldNamed: aString ifAbsent: aBlock [ 131 | ^worlds at: aString ifAbsent: aBlock 132 | ] 133 | 134 | { #category : #accessing } 135 | TWMWorldManager >> worlds [ 136 | ^worlds 137 | ] 138 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest, 3 | #superclass : #WMWithTwoBrowsersAndTwoWorkspacesTest, 4 | #instVars : [ 5 | 'worldRecorder' 6 | ], 7 | #category : 'TWM-Tests' 8 | } 9 | 10 | { #category : #running } 11 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> setUp [ 12 | super setUp. 13 | 14 | workspace1 bounds: (10@10 corner: 200@200). 15 | workspace2 bounds: (20@20 corner: 150@150). 16 | browser1 minimize. 17 | browser2 expandBoxHit. 18 | workspace2 activate. 19 | 20 | worldRecorder := TWMWorldRecorder of: testWorld. 21 | windowManager worldRecorder: worldRecorder. 22 | self assert: {workspace2. workspace1. browser2} equals: windowManager visibleWindows. 23 | 24 | windowManager minimizeAllWindows. 25 | windowManager tileWorkspaces. 26 | worldRecorder snapshot. 27 | self assert: {workspace2. workspace1} equals: windowManager visibleWindows. 28 | self assert: {workspace2. workspace1} equals: (worldRecorder currentSnapshot visibleWindows). 29 | 30 | windowManager minimizeAllWindows. 31 | windowManager tileBrowsers. 32 | worldRecorder snapshot. 33 | self assert: {browser2. browser1} equals: windowManager visibleWindows. 34 | 35 | windowManager minimizeAllWindows. 36 | self assert: {} equals: windowManager visibleWindows. 37 | ] 38 | 39 | { #category : #tests } 40 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardFourTimesShouldKeepLastRestore [ 41 | worldRecorder backward backward backward backward. 42 | self assert: {workspace2. workspace1. browser2} equals: windowManager visibleWindows. 43 | ] 44 | 45 | { #category : #tests } 46 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardOnceShouldRestoreBrowsers [ 47 | worldRecorder backward. 48 | self assert: {browser2. browser1.} equals: windowManager visibleWindows. 49 | ] 50 | 51 | { #category : #tests } 52 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardOnceThenForwardShouldRestoreAllMinimize [ 53 | worldRecorder backward forward. 54 | self assert: {} equals: windowManager visibleWindows. 55 | ] 56 | 57 | { #category : #tests } 58 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardThenOpenWindowThenBackwardShouldRestoreBrowsers [ 59 | | newWindow | 60 | worldRecorder backward. 61 | 62 | newWindow := SystemWindow new openInWorld: testWorld; yourself. 63 | worldRecorder backward. 64 | 65 | self assert: {browser2. browser1. newWindow} equals: windowManager visibleWindows. 66 | ] 67 | 68 | { #category : #tests } 69 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardThreeTimesShouldRestoreWorkspacesAndBrowserTwo [ 70 | worldRecorder backward backward backward. 71 | self assert: {workspace2. workspace1. browser2} equals: windowManager visibleWindows. 72 | ] 73 | 74 | { #category : #tests } 75 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardTwiceShouldRestoreWorkspaces [ 76 | worldRecorder backward. 77 | worldRecorder backward. 78 | 79 | self assert: {workspace2. workspace1.} equals: windowManager visibleWindows. 80 | ] 81 | 82 | { #category : #tests } 83 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testBackwardTwiceThenForwardShouldRestoreBrowsers [ 84 | worldRecorder backward backward forward. 85 | 86 | self assert: {browser2. browser1.} equals: windowManager visibleWindows. 87 | ] 88 | 89 | { #category : #tests } 90 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testDeleteCurrentSnapshotThenBackwardShouldRestoreWorkspaces [ 91 | worldRecorder deleteCurrentSnapshot backward. 92 | self assert: {workspace2. workspace1.} equals: windowManager visibleWindows. 93 | ] 94 | 95 | { #category : #tests } 96 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testDeleteCurrentSnapshotWhenRemainsOnlyOne [ 97 | | recorder | 98 | recorder := TWMWorldRecorder of: testWorld. 99 | self assert: 1 equals: recorder snapshots size. 100 | recorder deleteCurrentSnapshot. 101 | self assert: 1 equals: recorder snapshots size. 102 | 103 | ] 104 | 105 | { #category : #tests } 106 | WMWithTwoBrowsersAndTwoWorkspacesSnapshotRecorderTest >> testForwardShouldKeepAllMinimize [ 107 | worldRecorder forward. 108 | self assert: {} equals: windowManager visibleWindows. 109 | ] 110 | -------------------------------------------------------------------------------- /packages/TWM-Tests/TWMWindowSnapshotOfFinderTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #TWMWindowSnapshotOfFinderTest, 3 | #superclass : #WMInANewWorldTestCase, 4 | #instVars : [ 5 | 'finder', 6 | 'snapshot' 7 | ], 8 | #category : 'TWM-Tests' 9 | } 10 | 11 | { #category : #running } 12 | TWMWindowSnapshotOfFinderTest >> setUp [ 13 | super setUp. 14 | 15 | finder := self newWindowFor: #FinderUI. 16 | finder 17 | activate; 18 | bounds: (10@10 corner: 120@120). 19 | 20 | snapshot := TWMWindowSnapshot of: finder. 21 | ] 22 | 23 | { #category : #tests } 24 | TWMWindowSnapshotOfFinderTest >> testRestoreAfterCloseShouldDoNothing [ 25 | finder delete. 26 | snapshot restore. 27 | self assert: {} equals: windowManager windows. 28 | ] 29 | 30 | { #category : #tests } 31 | TWMWindowSnapshotOfFinderTest >> testRestoreAfterMaximizeShouldUnmaximizeIt [ 32 | finder maximize. 33 | snapshot restore. 34 | 35 | self assert: (10@10 corner: 120@120) equals: finder bounds. 36 | self deny: finder isMaximized. 37 | self deny: finder isMinimized. 38 | ] 39 | 40 | { #category : #tests } 41 | TWMWindowSnapshotOfFinderTest >> testRestoreAfterMinimizeShouldExpandIt [ 42 | finder minimize. 43 | snapshot restore. 44 | 45 | self assert: (10@10 corner: 120@120) equals: finder bounds. 46 | self deny: finder isMinimized. 47 | self deny: finder isMaximized. 48 | ] 49 | 50 | { #category : #tests } 51 | TWMWindowSnapshotOfFinderTest >> testRestoreAfterResizeShouldMoveItBackToSnapshot [ 52 | finder bounds: (50@50 corner: 180@230). 53 | self assert: (50@50 corner: 180@230) equals: finder bounds. 54 | 55 | snapshot restore. 56 | self assert: (10@10 corner: 120@120) equals: finder bounds. 57 | ] 58 | 59 | { #category : #tests } 60 | TWMWindowSnapshotOfFinderTest >> testRestoreWithoutMovingShouldKeepFinderAtItsPlace [ 61 | snapshot restore. 62 | self assert: (10@10 corner: 120@120) equals: finder bounds. 63 | ] 64 | 65 | { #category : #tests } 66 | TWMWindowSnapshotOfFinderTest >> testShouldBeEqualsAnotherSnapshotWithoutMoving [ 67 | self assert: snapshot equals: (TWMWindowSnapshot of: finder) 68 | ] 69 | 70 | { #category : #tests } 71 | TWMWindowSnapshotOfFinderTest >> testShouldNotBeEqualsAnotherSnapshotAfterMaximize [ 72 | finder maximize. 73 | self deny: snapshot = (TWMWindowSnapshot of: finder) 74 | ] 75 | 76 | { #category : #tests } 77 | TWMWindowSnapshotOfFinderTest >> testShouldNotBeEqualsAnotherSnapshotAfterMinimize [ 78 | finder minimize. 79 | self deny: snapshot = (TWMWindowSnapshot of: finder) 80 | ] 81 | 82 | { #category : #tests } 83 | TWMWindowSnapshotOfFinderTest >> testShouldNotBeEqualsAnotherSnapshotAfterMoving [ 84 | finder bounds: (50@50 corner: 205@190). 85 | self deny: snapshot = (TWMWindowSnapshot of: finder) 86 | ] 87 | 88 | { #category : #tests } 89 | TWMWindowSnapshotOfFinderTest >> testSnapshotMaximizedThenRestoreFromMinimizeShouldMaximizeIt [ 90 | finder maximize. 91 | snapshot snapshot: finder. 92 | finder minimize. 93 | snapshot restore. 94 | self assert: finder isMaximized. 95 | ] 96 | 97 | { #category : #tests } 98 | TWMWindowSnapshotOfFinderTest >> testSnapshotMaximizedThenRestoreFromUnMaximizedShouldMaximizeIt [ 99 | finder maximize. 100 | 101 | snapshot snapshot: finder. 102 | finder expandBoxHit. 103 | self deny: finder isMaximized. 104 | 105 | snapshot restore. 106 | self assert: finder isMaximized. 107 | ] 108 | 109 | { #category : #tests } 110 | TWMWindowSnapshotOfFinderTest >> testSnapshotMaximizedThenRestoreShouldKeeptItMaximized [ 111 | finder maximize. 112 | snapshot snapshot: finder. 113 | 114 | snapshot restore. 115 | self assert: finder isMaximized. 116 | ] 117 | 118 | { #category : #tests } 119 | TWMWindowSnapshotOfFinderTest >> testSnapshotMinimizedThenRestoreFromMaximizeShouldMinimizeIt [ 120 | finder minimize. 121 | snapshot snapshot: finder. 122 | finder maximize. 123 | snapshot restore. 124 | self assert: finder isMinimized. 125 | ] 126 | 127 | { #category : #tests } 128 | TWMWindowSnapshotOfFinderTest >> testSnapshotMinimizedThenRestoreFromUnMinimizedShouldMinimizeIt [ 129 | finder minimize. 130 | snapshot snapshot: finder. 131 | finder expandBoxHit. 132 | snapshot restore. 133 | self assert: finder isMinimized. 134 | ] 135 | 136 | { #category : #tests } 137 | TWMWindowSnapshotOfFinderTest >> testSnapshotMinimizedThenRestoreShouldKeeptItMinimized [ 138 | finder minimize. 139 | snapshot snapshot: finder. 140 | 141 | snapshot restore. 142 | self assert: finder isMinimized. 143 | ] 144 | 145 | { #category : #tests } 146 | TWMWindowSnapshotOfFinderTest >> testTilingWMBrowsersShouldReturnFinder [ 147 | self assert: {finder} equals: windowManager browsers. 148 | ] 149 | -------------------------------------------------------------------------------- /packages/TWM-Tests/TWMBarInANewWorldTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #TWMBarInANewWorldTest, 3 | #superclass : #WMInANewWorldTestCase, 4 | #traits : 'TWMTestHelpers', 5 | #classTraits : 'TWMTestHelpers classTrait', 6 | #instVars : [ 7 | 'twmBar', 8 | 'classFactory', 9 | 'testClassWithButtons' 10 | ], 11 | #category : 'TWM-Tests' 12 | } 13 | 14 | { #category : #running } 15 | TWMBarInANewWorldTest >> setUp [ 16 | super setUp. 17 | classFactory := ClassFactoryForTestCase new. 18 | testClassWithButtons := classFactory newClass. 19 | testClassWithButtons class 20 | compile: 'buttonTestRunner: aBuilder 21 | 22 | aBuilder 23 | action: [TestRunner open]; 24 | help: ''test open TestRunner''; 25 | icon: TestRunner taskbarIcon'; 26 | compile: 'buttonBrowser: aBuilder 27 | 28 | aBuilder 29 | action: [Browser open]; 30 | help: ''test open Browser''; 31 | priority: 100'; 32 | compile: 'buttonTranscript: aBuilder 33 | 34 | aBuilder 35 | action: [Transcript open]; 36 | help: ''test open Transcript''; 37 | priority: 5'. 38 | twmBar := TWMBar new openInWorld: testWorld. 39 | ] 40 | 41 | { #category : #running } 42 | TWMBarInANewWorldTest >> tearDown [ 43 | twmBar close. 44 | 45 | "So the pragmas are removed from the real bars (ok, hackish)" 46 | testClassWithButtons class 47 | compile: 'buttonTestRunner: aBuilder'; 48 | compile: 'buttonBrowser: aBuilder'; 49 | compile: 'buttonTranscript: aBuilder'. 50 | 51 | classFactory cleanUp. 52 | super tearDown. 53 | ] 54 | 55 | { #category : #'tests-pragma-twmButton' } 56 | TWMBarInANewWorldTest >> testBarShouldContainAButtonToOpenTestRunner [ 57 | self deny: (self iconicButtonWithTarget: [TestRunner open]) isNil. 58 | ] 59 | 60 | { #category : #'tests-pragma-twmButton' } 61 | TWMBarInANewWorldTest >> testBarShouldContainAButtonToOpenTranscript [ 62 | self deny: (self iconicButtonWithTarget: [Transcript open]) isNil. 63 | ] 64 | 65 | { #category : #tests } 66 | TWMBarInANewWorldTest >> testBrowserMenuShouldContainsNewBrowserEntry [ 67 | self assertMenuWithIcon: twmBar browsersMenuIcon containsItemNamed: 'New browser'. 68 | ] 69 | 70 | { #category : #tests } 71 | TWMBarInANewWorldTest >> testCustomButtonOrderShouldBeTestRunnerThenTranscriptThenBrowser [ 72 | | testRunnerIndex transcriptIndex browserIndex | 73 | testRunnerIndex := self twmBar dock allMorphs indexOf: (self iconicButtonWithTarget: [TestRunner open]). 74 | transcriptIndex := self twmBar dock allMorphs indexOf: (self iconicButtonWithTarget: [Transcript open]). 75 | browserIndex := self twmBar dock allMorphs indexOf: (self iconicButtonWithTarget: [Browser open]). 76 | 77 | self assert: (testRunnerIndex < transcriptIndex). 78 | self assert: (transcriptIndex < browserIndex). 79 | ] 80 | 81 | { #category : #tests } 82 | TWMBarInANewWorldTest >> testMonticelloMenuShouldContainsNewMonticelloBrowserEntry [ 83 | self assertMenuWithIcon: twmBar monticelloMenuIcon containsItemNamed: 'New Monticello browser'. 84 | ] 85 | 86 | { #category : #tests } 87 | TWMBarInANewWorldTest >> testRebuildContentAfterAddingAMorphShouldRemoveIt [ 88 | | morph | 89 | morph := Morph new. 90 | twmBar dock addMorph: morph. 91 | self assert: (twmBar dock submorphs includes: morph). 92 | 93 | twmBar rebuildDockContent. 94 | self deny: (twmBar dock submorphs includes: morph). 95 | ] 96 | 97 | { #category : #'tests-pragma-twmButton' } 98 | TWMBarInANewWorldTest >> testWhenANewButtonMethodIsAddedTheBarShouldBeUpdated [ 99 | classFactory newClass class 100 | compile: 'iWantAButton: aBuilder 101 | 102 | aBuilder 103 | action: [1+1]'. 104 | self deny: (self iconicButtonWithTarget: [1+1]) isNil. 105 | ] 106 | 107 | { #category : #'tests-pragma-twmButton' } 108 | TWMBarInANewWorldTest >> testWhenAPragmaIsRemovedBarShouldBeUpdated [ 109 | testClassWithButtons class 110 | compile: 'buttonTestRunner: aBuilder 111 | aBuilder 112 | action: [TestRunner open]; 113 | help: ''test open TestRunner''; 114 | icon: TestRunner taskbarIcon'. 115 | self assert: (self iconicButtonWithTarget: [TestRunner open]) isNil. 116 | ] 117 | 118 | { #category : #tests } 119 | TWMBarInANewWorldTest >> testWindowsMenuShouldContainsMinimizeAllEntry [ 120 | self assertMenuWithIcon: twmBar windowsIcon containsItemNamed: 'Minimize all windows'. 121 | ] 122 | 123 | { #category : #tests } 124 | TWMBarInANewWorldTest >> testWorkspaceMenuShouldContainsNewWorkspaceEntry [ 125 | self assertMenuWithIcon: twmBar workspacesMenuIcon containsItemNamed: 'New workspace'. 126 | ] 127 | 128 | { #category : #requirements } 129 | TWMBarInANewWorldTest >> twmBar [ 130 | ^ twmBar 131 | ] 132 | -------------------------------------------------------------------------------- /packages/TWM-KeyMapping/TWMKeymapping.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I build and handle TilingWM shortcuts in Settings Browser. 3 | 4 | Depends on KeyMapping. See #shortcuts for all shortcuts defined. 5 | " 6 | Class { 7 | #name : #TWMKeymapping, 8 | #superclass : #Object, 9 | #category : 'TWM-KeyMapping' 10 | } 11 | 12 | { #category : #shortcuts } 13 | TWMKeymapping class >> buildKeyMappingOn: aBuilder [ 14 | 15 | "See shortucts accessor to add/change a shortcut " 16 | 17 | 18 | self shortcutsActionAndKeysDo: [:action :keys :description| 19 | " self halt." 20 | (aBuilder shortcut: action) 21 | category: self shortcutCategory 22 | default: keys 23 | do: [ self windowManager perform: action ] 24 | description: description. 25 | ]. 26 | 27 | 28 | aBuilder setAsGlobalCategory: self shortcutCategory. 29 | 30 | ] 31 | 32 | { #category : #shortcuts } 33 | TWMKeymapping class >> buildSettingsOn: aBuilder [ 34 | 35 | "See shortucts accessor to add/change a shortcut " 36 | 37 | (aBuilder group: #twmShortcuts) 38 | label: 'Key mapping' translated; 39 | description: 'Tiling Window Manager shortcuts' translated; 40 | parent: #twm; 41 | order: 10; 42 | with: [ 43 | self shortcutsActionAndDescriptionDo: [: aName :aDescription| 44 | (aBuilder shortcut: aName) 45 | shortcutName: aName; 46 | category: self shortcutCategory; 47 | label: aDescription ]. 48 | ]. 49 | ] 50 | 51 | { #category : #accessing } 52 | TWMKeymapping class >> shortcutCategory [ 53 | ^ #twmShortcuts 54 | ] 55 | 56 | { #category : #accessing } 57 | TWMKeymapping class >> shortcuts [ 58 | self flag: #TODO. "These mappings have to be redone with the new KM ways of Pharo5" 59 | ^ { 60 | #minimizeAllWindows -> 'Minimize all windows' -> [$r command, $m command]. 61 | #maximizeAllWindows -> 'Maximize all windows' -> [$r command, $m shift command]. 62 | #tileVisibleWindows -> 'Tile visible windows' -> [$r command, $t command]. 63 | #tileLastUsedWindows -> 'Tile last used windows' -> [$r command, $l command]. 64 | #tileBrowsers -> 'Tile browsers' -> [$r command, $b command]. 65 | #tileWorkspaces -> 'Tile workspaces' -> [$r command, $z command]. 66 | #tileTesters -> 'Tile testers' -> [$r command, $u command]. 67 | #tileMonticellos -> 'Tile monticellos' -> [$r command, $c command]. 68 | #tileInspectors -> 'Tile inspectors' -> [$r command, $i command]. 69 | #tileDebuggers -> 'Tile debuggers' -> [$r command, $d command]. 70 | #tileChanges -> 'Tile changes' -> [$r command, $c shift command]. 71 | #tileTools -> 'Tile tools' -> [$r command, $t shift command]. 72 | #tileSystem -> 'Tile system windows' -> [$r command, $y command]. 73 | #snapshotWorld -> 'Snapshot current world state' -> [$r command, $s command]. 74 | #worldBackward -> 'Move to previous world state' -> [$r command, $p command]. 75 | #worldForward -> 'Move to next world state' -> [$r command, $n command]. 76 | #deleteCurrentSnapshot -> 'Delete current world state' -> [$r command, $d shift command]. 77 | #topWindowMoveLeft -> 'Move window to left area' -> [$r command, $1]. 78 | #topWindowMoveRight -> 'Move window to right area' -> [$r command, $2]. 79 | #topWindowMoveTop -> 'Move window to top area' -> [$r command, $3]. 80 | #topWindowMoveBottom -> 'Move window to bottom area' -> [$r command, $4]. 81 | #topWindowMoveTopLeft -> 'Move window to top left area' -> [$r command, $5]. 82 | #topWindowMoveTopRight -> 'Move window to top right area' -> [$r command, $6]. 83 | #topWindowMoveBottomLeft -> 'Move window to bottom left area' -> [$r command, $7]. 84 | #topWindowMoveBottomRight -> 'Move window to bottom right area' -> [$r command, $8]. 85 | #cycleClockwise -> 'Last visible window on stack come to top' -> [$r command, $>]. 86 | #cycleCounterClockwise -> 'First visible window on stack go to bottom' -> [$r command, $<]. 87 | #switchToNextWorld -> 'Switch to next world' -> [$r command, $r command] 88 | } 89 | ] 90 | 91 | { #category : #enumerating } 92 | TWMKeymapping class >> shortcutsActionAndDescriptionDo: aBlock [ 93 | self shortcuts do: [:actionDescShortcut| 94 | aBlock 95 | value: actionDescShortcut key key 96 | value: actionDescShortcut key value. 97 | ]. 98 | ] 99 | 100 | { #category : #enumerating } 101 | TWMKeymapping class >> shortcutsActionAndKeysDo: aBlock [ 102 | self shortcuts do: [:actionDescShortcut| 103 | aBlock 104 | value: actionDescShortcut key key 105 | value: actionDescShortcut value value 106 | value: actionDescShortcut key value. 107 | ]. 108 | ] 109 | 110 | { #category : #enumerating } 111 | TWMKeymapping class >> shortcutsDo: aBlock [ 112 | self shortcuts do: [:actionDescShortcut| |action description shortcutBlock| 113 | action := actionDescShortcut key key. 114 | description := actionDescShortcut key value. 115 | shortcutBlock := actionDescShortcut key value. "because Character>>#command is not in PharoCore" 116 | ]. 117 | ] 118 | 119 | { #category : #accessing } 120 | TWMKeymapping class >> windowManager [ 121 | ^ TilingWM instanceForCurrentWorld 122 | ] 123 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWithInspectorTranscriptAndMonticello.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMWithInspectorTranscriptAndMonticello, 3 | #superclass : #WMInANewWorldTestCase, 4 | #instVars : [ 5 | 'transcript', 6 | 'monticello', 7 | 'inspector' 8 | ], 9 | #category : 'TWM-Tests' 10 | } 11 | 12 | { #category : #asserting } 13 | WMWithInspectorTranscriptAndMonticello >> assertWindowFillArea: aWindow [ 14 | self assert: (0@0 extent: 200@200) equals: aWindow bounds. 15 | self assert: aWindow isActive. 16 | ] 17 | 18 | { #category : #running } 19 | WMWithInspectorTranscriptAndMonticello >> setUp [ 20 | super setUp. 21 | 22 | inspector := self newWindowFor: #EyeInspectorThatFixesInitialExtentForTesting. 23 | transcript := self newWindowForModelClass: (Smalltalk at: #Transcript) class. 24 | monticello := self newWindowFor: #MCWorkingCopy. 25 | ] 26 | 27 | { #category : #'tile tests' } 28 | WMWithInspectorTranscriptAndMonticello >> testMonticellosShouldContainsMCBrowserWindow [ 29 | self assert: {monticello} equals: windowManager monticellos. 30 | ] 31 | 32 | { #category : #'tile tests' } 33 | WMWithInspectorTranscriptAndMonticello >> testTileInspectorsMaximizedShouldDeMaximizedIt [ 34 | inspector maximize. 35 | windowManager tileInspectors. 36 | self deny: inspector isMaximized. 37 | ] 38 | 39 | { #category : #'tile tests' } 40 | WMWithInspectorTranscriptAndMonticello >> testTileInspectorsShouldPutInspectorFullArea [ 41 | windowManager tileInspectors. 42 | self assertWindowFillArea: inspector. 43 | ] 44 | 45 | { #category : #'tile tests' } 46 | WMWithInspectorTranscriptAndMonticello >> testTileMonticellosShouldPutMCFullArea [ 47 | windowManager tileMonticellos. 48 | self assertWindowFillArea: monticello. 49 | ] 50 | 51 | { #category : #'tile tests' } 52 | WMWithInspectorTranscriptAndMonticello >> testTileToolsShouldPutTranscriptFullArea [ 53 | windowManager tileTools. 54 | self assertWindowFillArea: transcript. 55 | ] 56 | 57 | { #category : #'tile tests' } 58 | WMWithInspectorTranscriptAndMonticello >> testTileVisibleWindowsShouldDistributeThemInOrderOfActivation [ 59 | inspector activate. 60 | transcript activate. 61 | monticello activate. 62 | windowManager tileVisibleWindows. 63 | self assert: (0@0 extent: 200@100) equals: monticello bounds. 64 | self assert: (0@100 extent: 100@100) equals: transcript bounds. 65 | self assert: (100@100 extent: 100@100) equals: inspector bounds. 66 | 67 | 68 | transcript activate. 69 | windowManager tileVisibleWindows. 70 | self assert: (0@0 extent: 200@100) equals: transcript bounds. 71 | self assert: (0@100 extent: 100@100) equals: monticello bounds. 72 | self assert: (100@100 extent: 100@100) equals: inspector bounds. 73 | 74 | ] 75 | 76 | { #category : #'tile tests' } 77 | WMWithInspectorTranscriptAndMonticello >> testTileVisibleWindowsWithVerticalLayoutStrategyShouldDistributeThemInOrderOfActivation [ 78 | inspector activate. 79 | transcript activate. 80 | monticello activate. 81 | TilingWM layoutStrategyClassName: #TWMVerticalLayoutStrategy. 82 | windowManager tileVisibleWindows. 83 | self assert: (0@0 extent: 100@200) equals: monticello bounds. 84 | self assert: (100@0 extent: 100@100) equals: transcript bounds. 85 | self assert: (100@100 extent: 100@100) equals: inspector bounds. 86 | 87 | ] 88 | 89 | { #category : #'move tests' } 90 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveBottomLeftShouldPlaceIt [ 91 | inspector activate. 92 | windowManager topWindowMoveBottomLeft. 93 | self assert: (0@100 extent: 100@100) equals: inspector bounds. 94 | ] 95 | 96 | { #category : #'move tests' } 97 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveBottomRightShouldPlaceIt [ 98 | inspector activate. 99 | windowManager topWindowMoveBottomRight. 100 | self assert: (100@100 extent: 100@100) equals: inspector bounds. 101 | ] 102 | 103 | { #category : #'move tests' } 104 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveBottomShouldPlaceIt [ 105 | inspector activate. 106 | windowManager topWindowMoveBottom. 107 | self assert: (0@100 extent: 200@100) equals: inspector bounds. 108 | ] 109 | 110 | { #category : #'move tests' } 111 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveLeftShouldPlaceIt [ 112 | inspector activate. 113 | windowManager topWindowMoveLeft. 114 | self assert: (0@0 extent: 100@200) equals: inspector bounds. 115 | ] 116 | 117 | { #category : #'move tests' } 118 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveRightShouldPlaceIt [ 119 | inspector activate. 120 | windowManager topWindowMoveRight. 121 | self assert: (100@0 extent: 100@200) equals: inspector bounds. 122 | ] 123 | 124 | { #category : #'move tests' } 125 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveTopLeftShouldPlaceIt [ 126 | inspector activate. 127 | windowManager topWindowMoveTopLeft. 128 | self assert: (0@0 extent: 100@100) equals: inspector bounds. 129 | ] 130 | 131 | { #category : #'move tests' } 132 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveTopRightShouldPlaceIt [ 133 | inspector activate. 134 | windowManager topWindowMoveTopRight. 135 | self assert: (100@0 extent: 100@100) equals: inspector bounds. 136 | ] 137 | 138 | { #category : #'move tests' } 139 | WMWithInspectorTranscriptAndMonticello >> testTopWindowMoveTopShouldPlaceIt [ 140 | inspector activate. 141 | windowManager topWindowMoveTop. 142 | self assert: (0@0 extent: 200@100) equals: inspector bounds. 143 | ] 144 | -------------------------------------------------------------------------------- /packages/TWM-Tests/WMWithTwoBrowsersAndTwoWorkspacesTest.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #WMWithTwoBrowsersAndTwoWorkspacesTest, 3 | #superclass : #WMInANewWorldTestCase, 4 | #instVars : [ 5 | 'browser1', 6 | 'browser2', 7 | 'workspace1', 8 | 'workspace2', 9 | 'backupNumberOfWindowsSetting' 10 | ], 11 | #category : 'TWM-Tests' 12 | } 13 | 14 | { #category : #running } 15 | WMWithTwoBrowsersAndTwoWorkspacesTest >> setUp [ 16 | super setUp. 17 | 18 | browser1 := self newBrowserIn: testWorld. 19 | browser2 := self newBrowserIn: testWorld. 20 | workspace1 := self newWorkspaceIn: testWorld. 21 | workspace1 model contents: '1+1'. 22 | 23 | workspace2 := self newWorkspaceIn: testWorld. 24 | 25 | backupNumberOfWindowsSetting := TilingWM numberOfLastUsedWindows. 26 | TilingWM numberOfLastUsedWindows: 2. 27 | ] 28 | 29 | { #category : #running } 30 | WMWithTwoBrowsersAndTwoWorkspacesTest >> tearDown [ 31 | browser1 delete. 32 | browser2 delete. 33 | workspace1 delete. 34 | workspace2 delete. 35 | testWorld delete. 36 | 37 | TilingWM numberOfLastUsedWindows: backupNumberOfWindowsSetting. 38 | ] 39 | 40 | { #category : #'filter tests' } 41 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testBrowsersShouldReturnBrowserOneAndTwo [ 42 | self assert: {browser2. browser1} equals: windowManager browsers. 43 | ] 44 | 45 | { #category : #'filter tests' } 46 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testCycleClockwiseShouldPutBrowser1BeforeAllOtherWindows [ 47 | windowManager cycleClockwise. 48 | self assert: {workspace1. browser2.browser1. workspace2.} equals: windowManager visibleWindows. 49 | ] 50 | 51 | { #category : #'filter tests' } 52 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testCycleCounterClockwiseShouldPutWorkspace2AfterAllOtherWindows [ 53 | windowManager cycleCounterClockwise. 54 | self assert: {browser1. workspace2. workspace1. browser2.} equals: windowManager visibleWindows. 55 | ] 56 | 57 | { #category : #'filter tests' } 58 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testNewWorldRecorderAndBackwardShouldCreateOnlyOneSnapshot [ 59 | | recorder | 60 | recorder := TWMWorldRecorder of: testWorld. 61 | recorder backward. 62 | self assert: 1 equals: recorder snapshots size. 63 | ] 64 | 65 | { #category : #'filter tests' } 66 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testNewWorldRecorderAndBackwardTwiceShouldCreateOnlyOneSnapshot [ 67 | | recorder | 68 | recorder := TWMWorldRecorder of: testWorld. 69 | recorder backward backward. 70 | self assert: 1 equals: recorder snapshots size. 71 | ] 72 | 73 | { #category : #'setting tests' } 74 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testNumberOfLastUsedWindowsShouldDefaultToThree [ 75 | TilingWM numberOfLastUsedWindows: nil. 76 | self assert: 3 equals: TilingWM numberOfLastUsedWindows. 77 | 78 | ] 79 | 80 | { #category : #'tile tests' } 81 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileBrowsersWithBrowserOneHiddenShouldShowIt [ 82 | browser1 hide. 83 | windowManager tileBrowsers. 84 | self assert: (windowManager visibleWindows includes: browser1). 85 | self assert: browser1 visible. 86 | ] 87 | 88 | { #category : #'tile tests' } 89 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileBrowsersWithBrowserOneMinimizedShouldRaiseIt [ 90 | browser1 minimize. 91 | windowManager tileBrowsers. 92 | self assert: (windowManager visibleWindows includes: browser1). 93 | ] 94 | 95 | { #category : #'setting tests' } 96 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileLastUsedWindowsShouldTileOnlyLastTwoWindowsUsed [ 97 | workspace1 activate. 98 | browser2 activate. 99 | workspace2 activate. 100 | browser1 activate. 101 | browser1 minimize. 102 | windowManager tileLastUsedWindows.. 103 | self assert: (0@0 extent: 200@100) equals: browser1 bounds. 104 | self assert: (0@100 extent: 200@100) equals: workspace2 bounds. 105 | 106 | ] 107 | 108 | { #category : #'setting tests' } 109 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileLastUsedWindowsWithVerticalLayoutStrategyShouldTileVerticallyLastTwoWindowsUsed [ 110 | workspace1 activate. 111 | browser2 activate. 112 | workspace2 activate. 113 | browser1 activate. 114 | browser1 minimize. 115 | 116 | TilingWM layoutStrategyClassName: #TWMVerticalLayoutStrategy. 117 | windowManager tileLastUsedWindows.. 118 | self assert: (0@0 extent: 100@200) equals: browser1 bounds. 119 | self assert: (100@0 extent: 100@200) equals: workspace2 bounds. 120 | ] 121 | 122 | { #category : #'tile tests' } 123 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileVisibleWindowsShouldPlaceThemInTwoColumnsAndRows [ 124 | windowManager tileVisibleWindows. 125 | self assert: (0@0 extent: 100@100) equals: workspace2 bounds. 126 | self assert: (100@0 extent: 100@100) equals: workspace1 bounds. 127 | self assert: (0@100 extent: 100@100) equals: browser2 bounds. 128 | self assert: (100@100 extent: 100@100) equals: browser1 bounds. 129 | ] 130 | 131 | { #category : #'tile tests' } 132 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileWorkspacesShouldPlaceThemInOneColumnAndTwoRows [ 133 | windowManager tileWorkspaces. 134 | self assert: (0@0 extent: 200@100) equals: workspace2 bounds. 135 | self assert: (0@100 extent: 200@100) equals: workspace1 bounds. 136 | ] 137 | 138 | { #category : #'tile tests' } 139 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testTileWorkspacesWithWorkspaceOneMinimizedShouldRaiseIt [ 140 | workspace1 minimize. 141 | windowManager tileWorkspaces. 142 | self assert: (windowManager visibleWindows includes: workspace1). 143 | ] 144 | 145 | { #category : #'filter tests' } 146 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testVisibleWindowsShouldReturnWorkspacesAndBrowsers [ 147 | self assert: {workspace2. workspace1. browser2. browser1.} equals: windowManager visibleWindows. 148 | ] 149 | 150 | { #category : #'filter tests' } 151 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testWithBrowserOneMinimizedBrowsersShouldReturnBrowserOneAndTwo [ 152 | browser1 minimize. 153 | self assert: {browser2. browser1} equals: windowManager browsers. 154 | ] 155 | 156 | { #category : #'filter tests' } 157 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testWithBrowserOneMinimizedVisibleWindowsShouldReturnAllButBrowserOne [ 158 | browser1 minimize. 159 | self assert: {workspace2. workspace1. browser2. } equals: windowManager visibleWindows. 160 | ] 161 | 162 | { #category : #'filter tests' } 163 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testWithWorkspaceOneMinimizedWorkspacesShouldReturnWorkspaceOneAndTwo [ 164 | workspace1 minimize. 165 | self assert: {workspace2. workspace1} equals: windowManager workspaces. 166 | ] 167 | 168 | { #category : #'filter tests' } 169 | WMWithTwoBrowsersAndTwoWorkspacesTest >> testWorkspacesShouldReturnWorkspaceOneAndTwo [ 170 | self assert: {workspace2. workspace1} equals: windowManager workspaces. 171 | ] 172 | -------------------------------------------------------------------------------- /packages/TWM-Core/TilingWM.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I'm a window manager that can place windows in rows and column so they can all be visibles. 3 | 4 | Try: 5 | (TilingWM forWorld: World) tileVisibleWindows. 6 | (TilingWM forWorld: World) tileBrowsers. 7 | (TilingWM forWorld: World) tileWorkspaces. 8 | " 9 | Class { 10 | #name : #TilingWM, 11 | #superclass : #Object, 12 | #instVars : [ 13 | 'world', 14 | 'worldRecorder' 15 | ], 16 | #classVars : [ 17 | 'LayoutStrategy', 18 | 'NumberOfLastUsedWindows' 19 | ], 20 | #category : 'TWM-Core' 21 | } 22 | 23 | { #category : #accessing } 24 | TilingWM class >> currentWorldSnapshots [ 25 | ^ self instanceForCurrentWorld snapshots 26 | ] 27 | 28 | { #category : #'layout strategy' } 29 | TilingWM class >> defaultLayoutStrategy [ 30 | ^ TWMHorizontalLayoutStrategy. 31 | ] 32 | 33 | { #category : #'initialize-release' } 34 | TilingWM class >> forWorld: aPasteUpMorph [ 35 | ^ self new 36 | world: aPasteUpMorph; 37 | yourself. 38 | ] 39 | 40 | { #category : #accessing } 41 | TilingWM class >> instanceForCurrentWorld [ 42 | ^ self allInstances detect: [:aTilingWM| aTilingWM world == World] 43 | ] 44 | 45 | { #category : #'layout strategy' } 46 | TilingWM class >> layoutStrategy [ 47 | LayoutStrategy ifNil: [LayoutStrategy := self defaultLayoutStrategy]. 48 | ^ LayoutStrategy. 49 | ] 50 | 51 | { #category : #'layout strategy' } 52 | TilingWM class >> layoutStrategyClassName [ 53 | ^ self layoutStrategy name. 54 | ] 55 | 56 | { #category : #'layout strategy' } 57 | TilingWM class >> layoutStrategyClassName: strategyClassName [ 58 | LayoutStrategy := (Smalltalk at: strategyClassName ifAbsent: self defaultLayoutStrategy). 59 | ] 60 | 61 | { #category : #settings } 62 | TilingWM class >> numberOfLastUsedWindows [ 63 | ^ NumberOfLastUsedWindows ifNil: [NumberOfLastUsedWindows := 3]. 64 | ] 65 | 66 | { #category : #settings } 67 | TilingWM class >> numberOfLastUsedWindows: anInteger [ 68 | ^ NumberOfLastUsedWindows := anInteger. 69 | ] 70 | 71 | { #category : #windows } 72 | TilingWM >> browsers [ 73 | ^ self windowsOfModels: #(Browser OBSystemBrowser OBCodeBrowser NautilusUI NautilusUI2 MessageListBrowser FinderUI). 74 | ] 75 | 76 | { #category : #windows } 77 | TilingWM >> changes [ 78 | ^ self windowsOfModels: #(DualChangeSorter ChangeList ChangeSorter). 79 | ] 80 | 81 | { #category : #move } 82 | TilingWM >> cycleClockwise [ 83 | |queue| 84 | self flag: #TODO. "Need some love as World windws isn't working" 85 | queue := LinkedList newFrom: self visibleWindows. 86 | queue addLast: queue removeFirst. 87 | self tileWindows: queue. 88 | ] 89 | 90 | { #category : #move } 91 | TilingWM >> cycleCounterClockwise [ 92 | |queue| 93 | queue := LinkedList newFrom: self visibleWindows. 94 | queue addFirst: queue removeLast. 95 | self tileWindows: queue. 96 | ] 97 | 98 | { #category : #windows } 99 | TilingWM >> debuggers [ 100 | ^ self windowsOfModels: #(Debugger TimeProfiler) 101 | ] 102 | 103 | { #category : #history } 104 | TilingWM >> deleteCurrentSnapshot [ 105 | worldRecorder deleteCurrentSnapshot. 106 | ] 107 | 108 | { #category : #windows } 109 | TilingWM >> inspectors [ 110 | ^ self windowsOfModels: #(Inspector EyeInspector) 111 | ] 112 | 113 | { #category : #accessing } 114 | TilingWM >> lastUsedWindows [ 115 | | lastWindows allWindows | 116 | allWindows := self windows. 117 | lastWindows := allWindows copyFrom: 1 to: (self class numberOfLastUsedWindows min: allWindows size). 118 | ^ lastWindows 119 | ] 120 | 121 | { #category : #accessing } 122 | TilingWM >> layoutStrategy [ 123 | ^ self class layoutStrategy new world: self world. 124 | ] 125 | 126 | { #category : #layout } 127 | TilingWM >> maximizeAllWindows [ 128 | "Make all windows maximize." 129 | 130 | world expandAll 131 | 132 | ] 133 | 134 | { #category : #layout } 135 | TilingWM >> minimizeAllWindows [ 136 | "Make all windows minimize." 137 | 138 | world collapseAll 139 | 140 | ] 141 | 142 | { #category : #windows } 143 | TilingWM >> monticellos [ 144 | ^ self windowsOfModels: #(MCTool MCPackageManager). 145 | ] 146 | 147 | { #category : #move } 148 | TilingWM >> newTopWindowBoundsInArea: aBlock [ 149 | SystemWindow topWindow ifNotNil: [ 150 | SystemWindow topWindow bounds: (aBlock value: world clearArea). ] 151 | ] 152 | 153 | { #category : #printing } 154 | TilingWM >> printWorldRecorderPositionOn: aStream [ 155 | self worldRecorder printPositionOn: aStream. 156 | ] 157 | 158 | { #category : #history } 159 | TilingWM >> snapshotWorld [ 160 | worldRecorder snapshot 161 | ] 162 | 163 | { #category : #history } 164 | TilingWM >> snapshots [ 165 | ^ worldRecorder snapshots 166 | ] 167 | 168 | { #category : #world } 169 | TilingWM >> switchToNextWorld [ 170 | TWMWorldManager instance switchToNextWorld 171 | ] 172 | 173 | { #category : #windows } 174 | TilingWM >> system [ 175 | ^ self windowsOfModels: #(SettingBrowser) 176 | ] 177 | 178 | { #category : #accessing } 179 | TilingWM >> taskbar [ 180 | ^ world submorphs detect: [:m| m isTaskbar] ifNone: [nil]. 181 | ] 182 | 183 | { #category : #windows } 184 | TilingWM >> testers [ 185 | ^ self windowsOfModels: #(TestRunner) 186 | ] 187 | 188 | { #category : #layout } 189 | TilingWM >> tileBrowsers [ 190 | self tileWindows: self browsers. 191 | 192 | ] 193 | 194 | { #category : #layout } 195 | TilingWM >> tileChanges [ 196 | self tileWindows: self changes. 197 | 198 | ] 199 | 200 | { #category : #layout } 201 | TilingWM >> tileDebuggers [ 202 | self tileWindows: self debuggers. 203 | 204 | ] 205 | 206 | { #category : #layout } 207 | TilingWM >> tileInspectors [ 208 | self tileWindows: self inspectors. 209 | 210 | ] 211 | 212 | { #category : #layout } 213 | TilingWM >> tileLastUsedWindows [ 214 | | lastWindows | 215 | lastWindows := self lastUsedWindows. 216 | self tileWindows: lastWindows 217 | ] 218 | 219 | { #category : #layout } 220 | TilingWM >> tileMonticellos [ 221 | self tileWindows: self monticellos. 222 | 223 | ] 224 | 225 | { #category : #layout } 226 | TilingWM >> tileSystem [ 227 | self tileWindows: self system. 228 | 229 | ] 230 | 231 | { #category : #layout } 232 | TilingWM >> tileTesters [ 233 | self tileWindows: self testers. 234 | 235 | ] 236 | 237 | { #category : #layout } 238 | TilingWM >> tileTools [ 239 | self tileWindows: self tools. 240 | 241 | ] 242 | 243 | { #category : #layout } 244 | TilingWM >> tileVisibleWindows [ 245 | self tileWindows: self visibleWindows. 246 | 247 | ] 248 | 249 | { #category : #layout } 250 | TilingWM >> tileWindows: windows [ 251 | self layoutStrategy tileWindows: windows. 252 | (self visibleWindows copyWithoutAll: windows) do: #minimize 253 | ] 254 | 255 | { #category : #layout } 256 | TilingWM >> tileWorkspaces [ 257 | self tileWindows: self workspaces. 258 | 259 | ] 260 | 261 | { #category : #windows } 262 | TilingWM >> tools [ 263 | ^ self windowsOfModels: #(TranscriptModel ThreadSafeTranscript FileList ProcessBrowser) 264 | ] 265 | 266 | { #category : #move } 267 | TilingWM >> topWindowMoveBottom [ 268 | self newTopWindowBoundsInArea: [:area| area leftCenter corner: area bottomRight]. 269 | ] 270 | 271 | { #category : #move } 272 | TilingWM >> topWindowMoveBottomLeft [ 273 | self newTopWindowBoundsInArea: [:area| area leftCenter corner: area bottomCenter]. 274 | ] 275 | 276 | { #category : #move } 277 | TilingWM >> topWindowMoveBottomRight [ 278 | self newTopWindowBoundsInArea: [:area| area center corner: area bottomRight]. 279 | ] 280 | 281 | { #category : #move } 282 | TilingWM >> topWindowMoveFull [ 283 | self newTopWindowBoundsInArea: [:area| area topLeft corner: area bottomRight]. 284 | ] 285 | 286 | { #category : #move } 287 | TilingWM >> topWindowMoveLeft [ 288 | self newTopWindowBoundsInArea: [:area| area topLeft corner: area bottomCenter]. 289 | ] 290 | 291 | { #category : #move } 292 | TilingWM >> topWindowMoveRight [ 293 | self newTopWindowBoundsInArea: [:area| area topCenter corner: area bottomRight]. 294 | ] 295 | 296 | { #category : #move } 297 | TilingWM >> topWindowMoveTop [ 298 | self newTopWindowBoundsInArea: [:area| area topLeft corner: area rightCenter]. 299 | ] 300 | 301 | { #category : #move } 302 | TilingWM >> topWindowMoveTop23 [ 303 | self newTopWindowBoundsInArea: [:area| area topLeft corner: ((area bottomRight) * (1@0.66))]. 304 | ] 305 | 306 | { #category : #move } 307 | TilingWM >> topWindowMoveTopLeft [ 308 | self newTopWindowBoundsInArea: [:area| area topLeft corner: area center]. 309 | ] 310 | 311 | { #category : #move } 312 | TilingWM >> topWindowMoveTopRight [ 313 | self newTopWindowBoundsInArea: [:area| area topCenter corner: area rightCenter]. 314 | ] 315 | 316 | { #category : #filter } 317 | TilingWM >> visibleWindows [ 318 | ^ self windows select: [:m| m isNotMinimized]. 319 | ] 320 | 321 | { #category : #filter } 322 | TilingWM >> windows [ 323 | ^ world systemWindows 324 | ] 325 | 326 | { #category : #filter } 327 | TilingWM >> windowsOfModels: listOfModels [ 328 | |existingClasses| 329 | existingClasses := listOfModels 330 | inject: OrderedCollection new 331 | into: [:foundClasses :className| |foundClass| 332 | foundClass := Smalltalk at: className ifAbsent: nil. 333 | foundClass ifNotNil: [foundClasses add: foundClass]. 334 | foundClasses. ]. 335 | 336 | ^ self windows select: [:window| 337 | existingClasses anySatisfy: [:aClass| 338 | window model isKindOf: aClass]]. 339 | ] 340 | 341 | { #category : #windows } 342 | TilingWM >> workspaces [ 343 | "Do both playground and plain old workspaces in case there are any." 344 | ^ self windowsOfModels: #(GTPlayground Workspace). 345 | 346 | ] 347 | 348 | { #category : #accessing } 349 | TilingWM >> world [ 350 | ^ world 351 | ] 352 | 353 | { #category : #accessing } 354 | TilingWM >> world: aPasteUpMorph [ 355 | world := aPasteUpMorph 356 | ] 357 | 358 | { #category : #history } 359 | TilingWM >> worldBackward [ 360 | self worldRecorder backward. 361 | ] 362 | 363 | { #category : #history } 364 | TilingWM >> worldForward [ 365 | self worldRecorder forward. 366 | ] 367 | 368 | { #category : #history } 369 | TilingWM >> worldRecorder [ 370 | ^ worldRecorder ifNil: [worldRecorder := TWMWorldRecorder of: world]. 371 | ] 372 | 373 | { #category : #history } 374 | TilingWM >> worldRecorder: aWorldRecorder [ 375 | worldRecorder := aWorldRecorder. 376 | ] 377 | -------------------------------------------------------------------------------- /packages/TWM-Theme/TWMUIThemeIcons.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #TWMUIThemeIcons, 3 | #superclass : #ThemeIcons, 4 | #category : 'TWM-Theme' 5 | } 6 | 7 | { #category : #'label-styles' } 8 | TWMUIThemeIcons class >> checkboxMarkerForm [ 9 | "Answer a new radio button marker form. We make it empty because we already have the selected radio button take care of the state." 10 | 11 | ^Form extent: 12@12 depth: 32 12 | ] 13 | 14 | { #category : #forms } 15 | TWMUIThemeIcons class >> checkboxSelectedForm [ 16 | ^ self form16x16FromContents: self checkboxSelectedFormContents 17 | 18 | ] 19 | 20 | { #category : #'as yet unclassified' } 21 | TWMUIThemeIcons class >> checkboxSelectedFormContents [ 22 | ^#( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4261412864 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4261412864 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4278190080 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4278190080 0 0 0 0 0 0 4261412864 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4261412864 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 23 | ] 24 | 25 | { #category : #forms } 26 | TWMUIThemeIcons class >> checkboxUnselectedForm [ 27 | ^ self form16x16FromContents: self checkboxUnselectedFormContents 28 | 29 | ] 30 | 31 | { #category : #'as yet unclassified' } 32 | TWMUIThemeIcons class >> checkboxUnselectedFormContents [ 33 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4261412864 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4261412864 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 0 0 4278190080 0 0 0 0 0 0 4261412864 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4261412864 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 34 | ] 35 | 36 | { #category : #'as yet unclassified' } 37 | TWMUIThemeIcons class >> form16x16FromContents: aByteArray [ 38 | ^ Form 39 | extent: 16@16 40 | depth: 32 41 | fromArray: aByteArray 42 | offset: 0@0 43 | ] 44 | 45 | { #category : #'label-styles' } 46 | TWMUIThemeIcons class >> menuPinForm [ 47 | ^self form16x16FromContents: self menuPinFormContents 48 | ] 49 | 50 | { #category : #forms } 51 | TWMUIThemeIcons class >> menuPinFormContents [ 52 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 83886080 100663296 83886080 0 0 0 0 0 0 0 0 0 0 0 0 1291845632 3774873600 4194304000 3774873600 788529152 0 0 0 0 0 0 0 0 0 0 1107296256 4278190080 4278190080 4278190080 4278190080 4278190080 788529152 0 0 0 0 0 0 0 0 83886080 3992977408 4278190080 4278190080 4278190080 4278190080 4278190080 3774873600 83886080 0 0 0 0 0 0 0 100663296 4194304000 4278190080 4278190080 4278190080 4278190080 4278190080 4194304000 100663296 0 0 0 0 0 0 0 83886080 3774873600 4278190080 4278190080 4278190080 4278190080 4278190080 3992977408 83886080 0 0 0 0 0 0 0 0 1291845632 4261412864 4278190080 4278190080 4278190080 4261412864 1107296256 0 0 0 0 0 0 0 0 0 0 1107296256 3992977408 4194304000 3774873600 1291845632 0 0 0 0 0 0 0 0 0 0 0 0 83886080 100663296 83886080 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 53 | ] 54 | 55 | { #category : #'label-styles' } 56 | TWMUIThemeIcons class >> radioButtonMarkerForm [ 57 | "Answer a new radio button marker form. We make it empty because we already have the selected radio button take care of the state." 58 | 59 | ^Form extent: 12@12 depth: 32 60 | ] 61 | 62 | { #category : #forms } 63 | TWMUIThemeIcons class >> radioButtonSelectedForm [ 64 | ^ self form16x16FromContents: self radioButtonSelectedFormContents 65 | ] 66 | 67 | { #category : #'as yet unclassified' } 68 | TWMUIThemeIcons class >> radioButtonSelectedFormContents [ 69 | ^#( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50331648 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 1023410176 3422946822 4043572228 4043572228 3422946822 1023410176 0 0 0 0 0 0 0 0 0 2214987270 4161078533 4284045657 4285690482 4285690482 4284045657 4161078533 1058280468 0 0 0 0 0 0 0 1023410176 4278190080 4285887861 4286611584 4286611584 4286611584 4286611584 4285887861 4278190080 1023410176 0 0 0 0 0 50331648 3422946822 4284045657 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4284045657 3422946822 50331648 0 0 0 0 0 4043572228 4285690482 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4285690482 4043572228 0 0 0 0 0 0 4043572228 4285690482 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4285690482 4043572228 0 0 0 0 0 33554432 3422946822 4284045657 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4284045657 3422946822 50331648 0 0 0 0 0 1006632960 4161078533 4285887861 4286611584 4286611584 4286611584 4286611584 4285887861 4278190080 1023410176 0 0 0 0 0 0 0 2214987270 4278190080 4284045657 4285690482 4285690482 4284045657 4161078533 2214987270 0 0 0 0 0 0 0 0 0 1006632960 3422946822 4043572228 4043572228 3422946822 1023410176 0 0 0 0 0 0 0 0 0 0 0 33554432 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 70 | ] 71 | 72 | { #category : #'as yet unclassified' } 73 | TWMUIThemeIcons class >> radioButtonUnselectedForm [ 74 | ^ self form16x16FromContents: self radioButtonUnselectedFormContents 75 | ] 76 | 77 | { #category : #'as yet unclassified' } 78 | TWMUIThemeIcons class >> radioButtonUnselectedFormContents [ 79 | ^#( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50331648 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 1023410176 3238002688 3909091328 3909091328 3238002688 1023410176 0 0 0 0 0 0 0 0 0 2097152000 3976200192 1275068416 452984832 452984832 1275068416 3976200192 872415232 0 0 0 0 0 0 0 1023410176 4278190080 335544320 0 0 0 0 335544320 4278190080 1023410176 0 0 0 0 0 50331648 3238002688 1275068416 0 0 0 0 0 0 1275068416 3238002688 50331648 0 0 0 0 0 3909091328 452984832 0 0 0 0 0 0 452984832 3909091328 0 0 0 0 0 0 3909091328 452984832 0 0 0 0 0 0 452984832 3909091328 0 0 0 0 0 33554432 3238002688 1275068416 0 0 0 0 0 0 1275068416 3238002688 50331648 0 0 0 0 0 1006632960 3992977408 335544320 0 0 0 0 335544320 4278190080 1023410176 0 0 0 0 0 0 0 2097152000 4278190080 1275068416 452984832 452984832 1275068416 3976200192 2097152000 0 0 0 0 0 0 0 0 0 1006632960 3238002688 3909091328 3909091328 3238002688 1023410176 0 0 0 0 0 0 0 0 0 0 0 33554432 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 80 | ] 81 | 82 | { #category : #'as yet unclassified' } 83 | TWMUIThemeIcons class >> radioSelectedForm [ 84 | ^ Form fromBinaryStream: ( Base64MimeConverter mimeDecodeToBytes: self radioSelectedFormContents readStream) 85 | 86 | ] 87 | 88 | { #category : #'as yet unclassified' } 89 | TWMUIThemeIcons class >> radioSelectedFormContents [ 90 | ^#( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50331648 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 1023410176 3422946822 4043572228 4043572228 3422946822 1023410176 0 0 0 0 0 0 0 0 0 2214987270 4161078533 4284045657 4285690482 4285690482 4284045657 4161078533 1058280468 0 0 0 0 0 0 0 1023410176 4278190080 4285887861 4286611584 4286611584 4286611584 4286611584 4285887861 4278190080 1023410176 0 0 0 0 0 50331648 3422946822 4284045657 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4284045657 3422946822 50331648 0 0 0 0 0 4043572228 4285690482 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4285690482 4043572228 0 0 0 0 0 0 4043572228 4285690482 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4285690482 4043572228 0 0 0 0 0 33554432 3422946822 4284045657 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4284045657 3422946822 50331648 0 0 0 0 0 1006632960 4161078533 4285887861 4286611584 4286611584 4286611584 4286611584 4285887861 4278190080 1023410176 0 0 0 0 0 0 0 2214987270 4278190080 4284045657 4285690482 4285690482 4284045657 4161078533 2214987270 0 0 0 0 0 0 0 0 0 1006632960 3422946822 4043572228 4043572228 3422946822 1023410176 0 0 0 0 0 0 0 0 0 0 0 33554432 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 91 | offset: 0@0 92 | ] 93 | 94 | { #category : #'as yet unclassified' } 95 | TWMUIThemeIcons class >> radioUnselectedForm [ 96 | ^ Form fromBinaryStream: ( Base64MimeConverter mimeDecodeToBytes: self radioUnselectedFormContents readStream) 97 | 98 | ] 99 | 100 | { #category : #'as yet unclassified' } 101 | TWMUIThemeIcons class >> radioUnselectedFormContents [ 102 | ^#( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 50331648 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 1023410176 3238002688 3909091328 3909091328 3238002688 1023410176 0 0 0 0 0 0 0 0 0 2097152000 3976200192 1275068416 452984832 452984832 1275068416 3976200192 872415232 0 0 0 0 0 0 0 1023410176 4278190080 335544320 0 0 0 0 335544320 4278190080 1023410176 0 0 0 0 0 50331648 3238002688 1275068416 0 0 0 0 0 0 1275068416 3238002688 50331648 0 0 0 0 0 3909091328 452984832 0 0 0 0 0 0 452984832 3909091328 0 0 0 0 0 0 3909091328 452984832 0 0 0 0 0 0 452984832 3909091328 0 0 0 0 0 33554432 3238002688 1275068416 0 0 0 0 0 0 1275068416 3238002688 50331648 0 0 0 0 0 1006632960 3992977408 335544320 0 0 0 0 335544320 4278190080 1023410176 0 0 0 0 0 0 0 2097152000 4278190080 1275068416 452984832 452984832 1275068416 3976200192 2097152000 0 0 0 0 0 0 0 0 0 1006632960 3238002688 3909091328 3909091328 3238002688 1023410176 0 0 0 0 0 0 0 0 0 0 0 33554432 0 0 50331648 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 103 | offset: 0@0 104 | ] 105 | 106 | { #category : #'label-styles' } 107 | TWMUIThemeIcons class >> windowCloseForm [ 108 | ^ self form16x16FromContents: self windowCloseFormContents 109 | ] 110 | 111 | { #category : #'as yet unclassified' } 112 | TWMUIThemeIcons class >> windowCloseFormContents [ 113 | ^#( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 167772160 0 0 0 0 0 0 0 0 167772160 3875536896 4076863488 234881024 0 234881024 2919235584 3858759680 0 0 0 0 0 0 0 0 402653184 3674210304 4261412864 3758096384 671088640 3758096384 4261412864 4278190080 335544320 0 0 0 0 0 0 0 0 352321536 3758096384 4143972352 4211081216 4143972352 3758096384 352321536 0 0 0 0 0 0 0 0 0 0 671088640 4211081216 4261412864 4211081216 671088640 0 0 0 0 0 0 0 0 0 0 352321536 3758096384 4143972352 4211081216 4143972352 3758096384 352321536 0 0 0 0 0 0 0 0 335544320 4278190080 4244635648 3758096384 671088640 3758096384 4143972352 3724541952 402653184 0 0 0 0 0 0 0 0 3892314112 2919235584 234881024 0 234881024 4278190080 1761607680 167772160 0 0 0 0 0 0 0 0 167772160 67108864 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 114 | ] 115 | 116 | { #category : #'as yet unclassified' } 117 | TWMUIThemeIcons class >> windowCloseInactiveForm [ 118 | ^ self form16x16FromContents: self windowCloseInactiveFromContents 119 | ] 120 | 121 | { #category : #'as yet unclassified' } 122 | TWMUIThemeIcons class >> windowCloseInactiveFromContents [ 123 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 176193664 0 0 0 0 0 0 0 0 176193664 3883958400 4085284992 243302528 0 243302528 2927657088 3867181184 0 0 0 0 0 0 0 0 411074688 3682631808 4269834368 3766517888 679049593 3766517888 4269834368 4286611584 343965824 0 0 0 0 0 0 0 0 360282489 3766517888 4152328063 4219436927 4152393856 3766517888 360282489 0 0 0 0 0 0 0 0 0 0 679049593 4219436927 4269834368 4219436927 679049593 0 0 0 0 0 0 0 0 0 0 360282489 3766517888 4152393856 4219436927 4152328063 3766517888 360282489 0 0 0 0 0 0 0 0 343965824 4286611584 4253057152 3766517888 679049593 3766517888 4152328063 3732963456 411074688 0 0 0 0 0 0 0 0 3900735616 2927657088 243302528 0 243302528 4286611584 1769897598 176193664 0 0 0 0 0 0 0 0 176193664 75530368 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 124 | ] 125 | 126 | { #category : #'label-styles' } 127 | TWMUIThemeIcons class >> windowMaximizeForm [ 128 | ^ self form16x16FromContents: self windowMaximizeFormContents 129 | ] 130 | 131 | { #category : #'as yet unclassified' } 132 | TWMUIThemeIcons class >> windowMaximizeFormContents [ 133 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 0 0 0 0 0 0 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 134 | 135 | ] 136 | 137 | { #category : #'as yet unclassified' } 138 | TWMUIThemeIcons class >> windowMaximizeInactiveForm [ 139 | ^ self form16x16FromContents: self windowMaximizeInactiveFormContents 140 | ] 141 | 142 | { #category : #'as yet unclassified' } 143 | TWMUIThemeIcons class >> windowMaximizeInactiveFormContents [ 144 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 0 0 0 0 0 0 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 145 | ] 146 | 147 | { #category : #'label-styles' } 148 | TWMUIThemeIcons class >> windowMenuForm [ 149 | ^self form16x16FromContents: self windowMenuFormContents 150 | ] 151 | 152 | { #category : #'as yet unclassified' } 153 | TWMUIThemeIcons class >> windowMenuFormContents [ 154 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 352321536 3556769792 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 3556769792 352321536 0 0 0 0 0 0 0 352321536 3556769792 4278190080 4278190080 4278190080 4278190080 3556769792 352321536 0 0 0 0 0 0 0 0 0 352321536 3556769792 4278190080 4278190080 3556769792 352321536 0 0 0 0 0 0 0 0 0 0 0 369098752 3556769792 3556769792 352321536 0 0 0 0 0 0 0 0 0 0 0 0 0 369098752 352321536 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 155 | ] 156 | 157 | { #category : #'as yet unclassified' } 158 | TWMUIThemeIcons class >> windowMenuInactiveForm [ 159 | ^self form16x16FromContents: self windowMenuInactiveFormContents 160 | ] 161 | 162 | { #category : #'as yet unclassified' } 163 | TWMUIThemeIcons class >> windowMenuInactiveFormContents [ 164 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 360282489 3565191296 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 3565191296 360282489 0 0 0 0 0 0 0 360282489 3565191296 4286611584 4286611584 4286611584 4286611584 3565191296 360282489 0 0 0 0 0 0 0 0 0 360282489 3565191296 4286611584 4286611584 3565191296 360282489 0 0 0 0 0 0 0 0 0 0 0 377520256 3565191296 3565191296 360282489 0 0 0 0 0 0 0 0 0 0 0 0 0 377520256 360282489 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 165 | ] 166 | 167 | { #category : #'label-styles' } 168 | TWMUIThemeIcons class >> windowMinimizeForm [ 169 | ^self form16x16FromContents: self windowMinimizeFormContents 170 | ] 171 | 172 | { #category : #'as yet unclassified' } 173 | TWMUIThemeIcons class >> windowMinimizeFormContents [ 174 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 0 0 0 0 0 0 0 0 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 4278190080 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 175 | ] 176 | 177 | { #category : #'as yet unclassified' } 178 | TWMUIThemeIcons class >> windowMinimizeInactiveForm [ 179 | ^self form16x16FromContents: self windowMinimizeInactiveFormContents 180 | ] 181 | 182 | { #category : #'as yet unclassified' } 183 | TWMUIThemeIcons class >> windowMinimizeInactiveFormContents [ 184 | ^ #( 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 0 0 0 0 0 0 0 0 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 4286611584 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0) 185 | ] 186 | -------------------------------------------------------------------------------- /packages/TWM-GUI/TWMBar.class.st: -------------------------------------------------------------------------------- 1 | " 2 | I create a simple dock for TilingWM actions. 3 | 4 | Open with: 5 | 6 | TWMBar open. 7 | " 8 | Class { 9 | #name : #TWMBar, 10 | #superclass : #Object, 11 | #instVars : [ 12 | 'dock', 13 | 'wm', 14 | 'worldRecorder', 15 | 'worldManager', 16 | 'buttonsCollector' 17 | ], 18 | #classVars : [ 19 | 'Default', 20 | 'ShowTWMBar' 21 | ], 22 | #category : 'TWM-GUI' 23 | } 24 | 25 | { #category : #'open/close' } 26 | TWMBar class >> close [ 27 | self default close. 28 | self reset. 29 | ] 30 | 31 | { #category : #defaults } 32 | TWMBar class >> default [ 33 | ^ Default ifNil: [Default := self new] 34 | ] 35 | 36 | { #category : #'open/close' } 37 | TWMBar class >> open [ 38 | ^ self default open. 39 | ] 40 | 41 | { #category : #defaults } 42 | TWMBar class >> reset [ 43 | "self reset" 44 | Default := nil. 45 | ] 46 | 47 | { #category : #settings } 48 | TWMBar class >> showTWMBar [ 49 | ^ ShowTWMBar ifNil: [ShowTWMBar := false]. 50 | ] 51 | 52 | { #category : #settings } 53 | TWMBar class >> showTWMBar: aBoolean [ 54 | (ShowTWMBar := aBoolean) 55 | ifTrue: [self open] 56 | ifFalse: [self close]. 57 | 58 | ^ ShowTWMBar 59 | ] 60 | 61 | { #category : #menus } 62 | TWMBar >> addWindows: windows toMenu: aMenu [ 63 | self addWindows: windows toMenu: aMenu withLabel: [:aWindow| aWindow label]. 64 | ] 65 | 66 | { #category : #menus } 67 | TWMBar >> addWindows: windows toMenu: aMenu withLabel: aBlock [ 68 | "aMenu addLine." 69 | windows do: [:aWindow| 70 | aMenu 71 | add: (aBlock value: aWindow) 72 | target: aWindow 73 | selector: #expandAndActivate. 74 | aMenu lastItem icon: aWindow taskbarIcon]. 75 | 76 | ] 77 | 78 | { #category : #'custom-buttons' } 79 | TWMBar >> allButtonBuilders [ 80 | ^ self allButtonPragmas 81 | collect: [:aPragma| |aButtonBuilder| 82 | aButtonBuilder := TWMBarButtonBuilder new. 83 | aPragma methodClass theNonMetaClass 84 | perform: aPragma selector 85 | with: aButtonBuilder. 86 | aButtonBuilder]. 87 | ] 88 | 89 | { #category : #'custom-buttons' } 90 | TWMBar >> allButtonPragmas [ 91 | ^ self buttonsCollector reset collected. 92 | ] 93 | 94 | { #category : #icon } 95 | TWMBar >> bottomIcon [ 96 | ^ self iconSubmorphBounds:[:aMorph| aMorph leftCenter corner: aMorph bottomRight ]. 97 | ] 98 | 99 | { #category : #icon } 100 | TWMBar >> bottomLeftIcon [ 101 | ^ self iconSubmorphBounds:[:aMorph| aMorph leftCenter corner: aMorph bottomCenter ]. 102 | ] 103 | 104 | { #category : #icon } 105 | TWMBar >> bottomRightIcon [ 106 | ^ self iconSubmorphBounds:[:aMorph| aMorph center corner: aMorph bottomRight ]. 107 | ] 108 | 109 | { #category : #icon } 110 | TWMBar >> browsersMenuIcon [ 111 | ^ Smalltalk tools browser taskbarIcon 112 | ] 113 | 114 | { #category : #factory } 115 | TWMBar >> buttonAction: aBlock icon: aForm balloon: aBalloon [ 116 | | button | 117 | button := IconicButton new 118 | target: aBlock; 119 | actionSelector: #value; 120 | labelGraphic: aForm; "labelGraphic: aForm or labelFromString: aBalloon" 121 | color: Color transparent. 122 | aBalloon ifNotNil: [ button setBalloonText: aBalloon ]. 123 | ^ button 124 | ] 125 | 126 | { #category : #'custom-buttons' } 127 | TWMBar >> buttonsCollector [ 128 | ^ buttonsCollector ifNil: [buttonsCollector := self newButtonsCollector] 129 | ] 130 | 131 | { #category : #'open/close' } 132 | TWMBar >> close [ 133 | dock ifNotNil: [ dock delete ]. 134 | ] 135 | 136 | { #category : #factory } 137 | TWMBar >> createNewWorldNamed: aString [ 138 | | newWorld | 139 | newWorld := self worldManager newWorldNamed: aString. 140 | TWMBar showTWMBar ifTrue: [ TWMBar new openInWorld: newWorld ]. 141 | self worldManager switchToWorld: newWorld. 142 | ] 143 | 144 | { #category : #'custom-buttons' } 145 | TWMBar >> customButtons [ 146 | ^ (self allButtonBuilders 147 | sort: [:a :b| a priority > b priority]) 148 | collect: [:aBuilder| aBuilder button] 149 | ] 150 | 151 | { #category : #icon } 152 | TWMBar >> deleteIcon [ 153 | ^ dock icons smallDeleteIcon 154 | ] 155 | 156 | { #category : #icon } 157 | TWMBar >> deleteSnapshotIcon [ 158 | ^ dock icons smallDeleteIcon. 159 | ] 160 | 161 | { #category : #accessing } 162 | TWMBar >> dock [ 163 | ^ dock 164 | ] 165 | 166 | { #category : #icon } 167 | TWMBar >> fullIcon [ 168 | ^ self iconSubmorphBounds:[:aMorph| aMorph topLeft corner: aMorph bottomRight ]. 169 | ] 170 | 171 | { #category : #icon } 172 | TWMBar >> iconSubmorphBounds: aBlock [ 173 | |icon| 174 | 175 | icon := Morph new 176 | color: Color transparent; 177 | extent: 16@16. 178 | icon addMorph: ( Morph new 179 | color: Color gray darker; 180 | bounds: (aBlock value: icon)). 181 | ^ icon imageForm. 182 | ] 183 | 184 | { #category : #accessing } 185 | TWMBar >> icons [ 186 | ^Smalltalk ui icons 187 | ] 188 | 189 | { #category : #icon } 190 | TWMBar >> leftIcon [ 191 | ^ self iconSubmorphBounds:[:aMorph| aMorph topLeft corner: aMorph bottomCenter ]. 192 | ] 193 | 194 | { #category : #icon } 195 | TWMBar >> maximizeAllWindowsIcon [ 196 | ^ dock icons windowMaximizeForm 197 | ] 198 | 199 | { #category : #icon } 200 | TWMBar >> minimizeAllWindowsIcon [ 201 | ^ dock icons windowMinimizeForm 202 | ] 203 | 204 | { #category : #icon } 205 | TWMBar >> monticelloMenuIcon [ 206 | ^ MCWorkingCopyBrowser taskbarIcon 207 | ] 208 | 209 | { #category : #icon } 210 | TWMBar >> multipleWorldIcon [ 211 | ^ self icons smallObjectsIcon 212 | ] 213 | 214 | { #category : #menus } 215 | TWMBar >> newBrowsersMenu [ 216 | "This is where we rebuild the menu for browsers" 217 | 218 | ^ self newMenu: #updateBrowsersMenu: icon: self browsersMenuIcon help: 'Browsers actions' 219 | ] 220 | 221 | { #category : #'custom-buttons' } 222 | TWMBar >> newButtonsCollector [ 223 | | collector | 224 | collector := (PragmaCollector filter: [ :pragma | 225 | pragma keyword = self pragmaButtonKeyword ]). 226 | collector whenChangedSend: #rebuildDockContent to: self. 227 | ^ collector 228 | ] 229 | 230 | { #category : #factory } 231 | TWMBar >> newFixedSpacer [ 232 | ^ AlignmentMorph new 233 | extent: 25@25; 234 | hResizing: #shrinkWrap; 235 | vResizing: #shrinkWrap; 236 | color: Color transparent. 237 | 238 | ] 239 | 240 | { #category : #icon } 241 | TWMBar >> newIconWithString: aString [ 242 | ^ ((SimpleButtonMorph new) 243 | extent: 16 @ 16; 244 | color: Color transparent; 245 | label: aString) imageForm 246 | ] 247 | 248 | { #category : #menus } 249 | TWMBar >> newMenu: aSelector icon: aForm help: aString [ 250 | ^ DockingBarMenuItemMorph new 251 | contents: ''; 252 | subMenu: (TWMUpdatingMenuMorph new updater: self updateSelector: aSelector); 253 | icon: aForm; 254 | setBalloonText: aString. 255 | ] 256 | 257 | { #category : #menus } 258 | TWMBar >> newMonticellosMenu [ 259 | ^ self newMenu: #updateMonticellosMenu: icon: self monticelloMenuIcon help: 'Monticello tools actions' 260 | ] 261 | 262 | { #category : #menus } 263 | TWMBar >> newMultipleWorldMenu [ 264 | ^ self newMenu: #updateMultipleWorldMenu: icon: self multipleWorldIcon help: 'Multiple world' 265 | ] 266 | 267 | { #category : #menus } 268 | TWMBar >> newOtherToolsMenu [ 269 | ^ self newMenu: #updateOtherToolsMenu: icon: self otherToolsMenuIcon help: 'Other tools actions' 270 | ] 271 | 272 | { #category : #factory } 273 | TWMBar >> newSpacer [ 274 | ^ AlignmentMorph newSpacer: Color transparent 275 | 276 | ] 277 | 278 | { #category : #menus } 279 | TWMBar >> newWindowsMenu [ 280 | ^ self newMenu: #updateWindowsMenu: icon: self windowsIcon help: 'All windows actions' 281 | ] 282 | 283 | { #category : #menus } 284 | TWMBar >> newWorkspacesMenu [ 285 | ^ self newMenu: #updateWorkspacesMenu: icon: self workspacesMenuIcon help: 'Playgrounds and Workspaces actions' 286 | ] 287 | 288 | { #category : #callback } 289 | TWMBar >> newWorld [ 290 | | worldName | 291 | worldName := (UIManager default request: 'Enter the new World name'). 292 | worldName ifNil: [ ^ self ]. 293 | self createNewWorldNamed: worldName. 294 | TaskbarMorph showTaskbarPreferenceChanged. 295 | ] 296 | 297 | { #category : #menus } 298 | TWMBar >> newWorldMenu [ 299 | ^ DockingBarMenuItemMorph new 300 | contents: ''; 301 | subMenu: (TWMUpdatingMenuMorph new updater: self updateSelector: #updateWorldMenu:); 302 | icon: self openWorldMenuIcon; 303 | setBalloonText: 'Open World menu'. 304 | ] 305 | 306 | { #category : #'open/close' } 307 | TWMBar >> open [ 308 | self openInWorld: World. 309 | 310 | ] 311 | 312 | { #category : #'open/close' } 313 | TWMBar >> openInWorld: aWorld [ 314 | wm := TilingWM forWorld: aWorld. 315 | dock := TWMDockingBarMorph new 316 | adhereToLeft; 317 | yourself. 318 | self rebuildDockContent. 319 | dock openInWorld: aWorld. 320 | 321 | ] 322 | 323 | { #category : #icon } 324 | TWMBar >> openNewIcon [ 325 | ^ self newIconWithString: '+'. 326 | ] 327 | 328 | { #category : #icon } 329 | TWMBar >> openWindowsMenuIcon [ 330 | ^ dock icons smallForwardIcon 331 | ] 332 | 333 | { #category : #icon } 334 | TWMBar >> openWorldMenuIcon [ 335 | ^ (Form 336 | extent: 16@22 337 | depth: 32 338 | fromArray: #( 16777215 16777215 16777215 16777215 16777215 16777215 133690800 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 100136368 83359152 234354096 150468016 536343984 33027504 133690800 33027504 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 603452848 1548898875 3241094689 3446171466 1329939761 217576880 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 3476502311 4286479706 4289243000 3713554239 988210340 586675632 251131312 16777215 16777215 16777215 83359152 217576880 351794608 502789552 637007280 771225008 3259253809 4289045365 4290821769 3646445374 16777216 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 1509949440 4096798498 4282400814 4283716412 4130090016 2423616595 637007280 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 1074728715 4177526784 4281150496 4278190080 4148840757 1006632960 335017392 737670576 301462960 16777215 16777215 16777215 16777215 16777215 16777215 1979711488 3472883712 4227858432 4280492825 4278190080 4262333962 3508082962 1778384896 16777215 234354096 318240176 83359152 16777215 16777215 16777215 16777215 1056964608 3439329280 4278190080 4279834898 4278190080 4278190080 3204777220 838860800 16777215 16777215 16777215 49804720 16777215 16777215 16777215 16777215 16777215 1107296256 3909091328 4279242763 4278190080 3388997632 1090519040 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 2130706432 4278190080 3574073350 1929379840 67108864 754974720 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 2650800128 2600468480 167772160 234881024 2634022912 2483027968 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 1526726656 100663296 2080374784 3707764736 4278190080 2634022912 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 1140850688 3489660928 4278190080 4278190080 3690987520 1107296256 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777216 3607101440 4278190080 3724541952 2264924160 301989888 318767104 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 587202560 3959422976 2432696320 301989888 16777215 184549376 3271557120 167772160 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 1358954496 1358954496 16777215 83886080 1811939328 3472883712 4278190080 771751936 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 67108864 134217728 2080374784 3573547008 4278190080 4278190080 4244635648 1275068416 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 1174405120 3506438144 4278190080 4278190080 4278190080 3942645760 2214592512 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 2868903936 4278190080 4278190080 3674210304 2399141888 587202560 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 3271557120 3489660928 1845493760 134217728 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 2952790016 251658240 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215 16777215) 339 | offset: 0@0) 340 | ] 341 | 342 | { #category : #icon } 343 | TWMBar >> otherToolsMenuIcon [ 344 | ^ dock icons smallDoItIcon 345 | ] 346 | 347 | { #category : #'custom-buttons' } 348 | TWMBar >> pragmaButtonKeyword [ 349 | ^ 'twmBarButton' 350 | ] 351 | 352 | { #category : #'open/close' } 353 | TWMBar >> rebuildDockContent [ 354 | 355 | dock 356 | removeAllMorphs; 357 | addMorph: (self buttonAction: [wm topWindowMoveTop23 ] icon: self top23Icon balloon: 'Make window top 2/3'); 358 | addMorph: (self buttonAction: [wm topWindowMoveFull ] icon: self fullIcon balloon: 'Make window full area'); 359 | addMorph: (self buttonAction: [wm topWindowMoveBottomLeft ] icon: self bottomLeftIcon balloon: 'Move window to bottom left area'); 360 | addMorph: (self buttonAction: [wm topWindowMoveBottomRight ] icon: self bottomRightIcon balloon: 'Move window to bottom right area'); 361 | addMorph: (self buttonAction: [wm topWindowMoveTopRight ] icon: self topRightIcon balloon: 'Move window to top right area'); 362 | addMorph: (self buttonAction: [wm topWindowMoveTopLeft ] icon: self topLeftIcon balloon: 'Move window to top left area'); 363 | 364 | addMorph: (self buttonAction: [wm topWindowMoveBottom ] icon: self bottomIcon balloon: 'Move window to bottom area'); 365 | addMorph: (self buttonAction: [wm topWindowMoveTop ] icon: self topIcon balloon: 'Move window to top area'); 366 | 367 | addMorph: (self buttonAction: [wm topWindowMoveRight ] icon: self rightIcon balloon: 'Move window to right area'); 368 | addMorph: (self buttonAction: [wm topWindowMoveLeft ] icon: self leftIcon balloon: 'Move window to left area'); 369 | 370 | addMorph: self newSpacer; 371 | addMorph: (LabelMorph new model: self; getTextSelector: #worldRecorderPosition); 372 | addMorph: (self buttonAction: [wm deleteCurrentSnapshot. self changed: #worldRecorderPosition] icon: self deleteSnapshotIcon balloon: 'Delete current snapshot of world state'); 373 | addMorph: (self buttonAction: [wm worldForward. self changed: #worldRecorderPosition] icon: self worldForwardIcon balloon: 'Undo restore previous world state'); 374 | addMorph: (self buttonAction: [wm worldBackward. self changed: #worldRecorderPosition] icon: self worldBackwardIcon balloon: 'Restore previous world state'); 375 | addMorph: (self buttonAction: [wm snapshotWorld. self changed: #worldRecorderPosition] icon: self snapshotWorldIcon balloon: 'Snapshot current world state'); 376 | addMorph: self newSpacer. 377 | 378 | "self customButtons do: [:aButton| self dock addMorph: aButton]." 379 | 380 | self dock 381 | addMorph: self newSpacer; 382 | 383 | addMorph: (self newMultipleWorldMenu); 384 | 385 | addMorph: self newFixedSpacer; 386 | 387 | addMorph: (self newOtherToolsMenu); 388 | addMorph: (self newMonticellosMenu); 389 | addMorph: (self newWorkspacesMenu); 390 | addMorph: (self newBrowsersMenu); 391 | addMorph: (self newWindowsMenu). 392 | 393 | " Until we can fix the World menu integration, this is disabled " 394 | "addMorph: self newFixedSpacer; 395 | 396 | addMorph: (self newWorldMenu)." 397 | ] 398 | 399 | { #category : #icon } 400 | TWMBar >> rightIcon [ 401 | ^ self iconSubmorphBounds:[:aMorph| aMorph topCenter corner: aMorph bottomRight ]. 402 | ] 403 | 404 | { #category : #icon } 405 | TWMBar >> snapshotWorldIcon [ 406 | ^ dock icons smallScreenshotIcon. 407 | ] 408 | 409 | { #category : #icon } 410 | TWMBar >> tileChangesIcon [ 411 | ^ ChangeList taskbarIcon 412 | ] 413 | 414 | { #category : #icon } 415 | TWMBar >> tileDebuggersIcon [ 416 | ^ Smalltalk tools debugger taskbarIcon 417 | ] 418 | 419 | { #category : #icon } 420 | TWMBar >> tileIcon [ 421 | ^ dock icons smallWindowIcon 422 | ] 423 | 424 | { #category : #icon } 425 | TWMBar >> tileInspectorsIcon [ 426 | ^ Smalltalk tools inspector taskbarIcon 427 | ] 428 | 429 | { #category : #icon } 430 | TWMBar >> tileLastUsedWindowsIcon [ 431 | ^ self newIconWithString: '««'. 432 | ] 433 | 434 | { #category : #icon } 435 | TWMBar >> tileSystemIcon [ 436 | ^ dock icons smallConfigurationIcon 437 | ] 438 | 439 | { #category : #icon } 440 | TWMBar >> tileTestersIcon [ 441 | ^ TestRunner taskbarIcon 442 | ] 443 | 444 | { #category : #icon } 445 | TWMBar >> tileVisibleWindowsIcon [ 446 | ^ dock icons smallWindowIcon 447 | ] 448 | 449 | { #category : #icon } 450 | TWMBar >> top23Icon [ 451 | ^ self iconSubmorphBounds:[:aMorph| aMorph topLeft corner: ((aMorph bottomRight)*(1@0.66)) ]. 452 | ] 453 | 454 | { #category : #icon } 455 | TWMBar >> topIcon [ 456 | ^ self iconSubmorphBounds:[:aMorph| aMorph topLeft corner: aMorph rightCenter ]. 457 | ] 458 | 459 | { #category : #icon } 460 | TWMBar >> topLeftIcon [ 461 | ^ self iconSubmorphBounds:[:aMorph| aMorph topLeft corner: aMorph center ]. 462 | ] 463 | 464 | { #category : #icon } 465 | TWMBar >> topRightIcon [ 466 | ^ self iconSubmorphBounds:[:aMorph| aMorph topCenter corner: aMorph rightCenter ]. 467 | ] 468 | 469 | { #category : #menus } 470 | TWMBar >> updateBrowsersMenu: aMenu [ 471 | 472 | aMenu 473 | add: 'Tile browsers' target: self windowManager selector: #tileBrowsers icon: self tileIcon; 474 | add: 'New browser' target: Smalltalk tools selector: #openClassBrowser icon: self openNewIcon. 475 | 476 | self 477 | addWindows: self windowManager browsers 478 | toMenu: aMenu. 479 | 480 | 481 | ] 482 | 483 | { #category : #menus } 484 | TWMBar >> updateMonticellosMenu: aMenu [ 485 | aMenu 486 | add: 'Tile Monticello tools' target: self windowManager selector: #tileMonticellos icon: self tileIcon; 487 | add: 'New Monticello browser' target: Smalltalk tools selector: #openMonticelloBrowser icon: self openNewIcon. 488 | 489 | self 490 | addWindows: self windowManager monticellos 491 | toMenu: aMenu. 492 | 493 | ] 494 | 495 | { #category : #menus } 496 | TWMBar >> updateMultipleWorldMenu: aMenu [ 497 | 498 | aMenu 499 | add: 'New World' target: self selector: #newWorld icon: self openNewIcon; 500 | add: 'Delete current World' target: TWMWorldManager instance selector: #deleteCurrentWorld icon: self deleteIcon."; 501 | addLine." 502 | 503 | self worldManager worlds keys do: [:aWorldName| 504 | 505 | aMenu 506 | add: aWorldName asString 507 | target: [self worldManager switchToWorldNamed: aWorldName ifAbsent: [Transcript show: 'Missing world', aWorldName;cr. 'Pharo']] 508 | selector: #value ]. 509 | ] 510 | 511 | { #category : #menus } 512 | TWMBar >> updateOtherToolsMenu: aMenu [ 513 | | windows | 514 | aMenu 515 | add: 'New TestRunner' target: Smalltalk tools selector: #openTestRunner icon: self openNewIcon. 516 | 517 | "All the windows that are not in the tooling" 518 | windows := ((self windowManager windows 519 | copyWithoutAll: self windowManager browsers) 520 | copyWithoutAll: self windowManager workspaces) 521 | copyWithoutAll: self windowManager monticellos. 522 | self 523 | addWindows: windows 524 | toMenu: aMenu. 525 | 526 | ] 527 | 528 | { #category : #menus } 529 | TWMBar >> updateWindowsMenu: aMenu [ 530 | aMenu 531 | add: 'Tile visible windows' target: self windowManager selector: #tileVisibleWindows icon: self tileVisibleWindowsIcon; 532 | add: 'Tile last used windows' target: self windowManager selector: #tileLastUsedWindows icon: self tileLastUsedWindowsIcon; 533 | add: 'Maximize all windows' target: self windowManager selector: #maximizeAllWindows icon: self maximizeAllWindowsIcon; 534 | add: 'Minimize all windows' target: self windowManager selector: #minimizeAllWindows icon: self minimizeAllWindowsIcon. 535 | 536 | 537 | self 538 | addWindows: self windowManager windows 539 | toMenu: aMenu. 540 | ] 541 | 542 | { #category : #menus } 543 | TWMBar >> updateWorkspacesMenu: aMenu [ 544 | aMenu 545 | add: 'Tile playgrounds' target: self windowManager selector: #tileWorkspaces icon: self tileIcon; 546 | add: 'New playground' target: Smalltalk tools selector: #openWorkspace icon: self openNewIcon. 547 | 548 | self 549 | addWindows: self windowManager workspaces 550 | toMenu: aMenu 551 | withLabel: [:aWindow| ((aWindow model respondsTo: #contentsFirstLine) 552 | ifTrue: [ 553 | | firstLine | 554 | firstLine := aWindow model contentsFirstLine. 555 | firstLine 556 | ifEmpty: [aWindow label] 557 | ifNotEmpty: [:contentsFirstLine | (contentsFirstLine truncateTo: 45) , ' ...'] 558 | ] 559 | ifFalse: [ 560 | aWindow label 561 | ] 562 | )] 563 | ] 564 | 565 | { #category : #menus } 566 | TWMBar >> updateWorldMenu: aMenu [ 567 | self windowManager world worldMenu items do: [:aMenuItem| aMenu addMenuItem: aMenuItem]. 568 | ] 569 | 570 | { #category : #accessing } 571 | TWMBar >> windowManager [ 572 | ^ wm ifNil: [wm := TilingWM forWorld: World]. 573 | ] 574 | 575 | { #category : #icon } 576 | TWMBar >> windowsIcon [ 577 | ^ dock icons smallWindowIcon 578 | ] 579 | 580 | { #category : #icon } 581 | TWMBar >> workspacesMenuIcon [ 582 | ^ Workspace taskbarIcon 583 | ] 584 | 585 | { #category : #icon } 586 | TWMBar >> worldBackwardIcon [ 587 | ^ self newIconWithString: '<'. 588 | ] 589 | 590 | { #category : #icon } 591 | TWMBar >> worldForwardIcon [ 592 | ^ self newIconWithString: '>'. 593 | ] 594 | 595 | { #category : #accessing } 596 | TWMBar >> worldManager [ 597 | ^ worldManager ifNil: [worldManager := TWMWorldManager instance]. 598 | ] 599 | 600 | { #category : #callback } 601 | TWMBar >> worldRecorderPosition [ 602 | ^ String streamContents: [:aStream| wm printWorldRecorderPositionOn: aStream] 603 | ] 604 | -------------------------------------------------------------------------------- /packages/TWM-Theme/TWMUITheme.class.st: -------------------------------------------------------------------------------- 1 | Class { 2 | #name : #TWMUITheme, 3 | #superclass : #UITheme, 4 | #category : 'TWM-Theme' 5 | } 6 | 7 | { #category : #accessing } 8 | TWMUITheme class >> baseColor [ 9 | ^ Color r: 190 g: 190 b: 190 range: 255 10 | ] 11 | 12 | { #category : #accessing } 13 | TWMUITheme class >> basePassiveBackgroundColor [ 14 | ^ Color r: 245 g: 245 b: 245 range: 255 15 | ] 16 | 17 | { #category : #accessing } 18 | TWMUITheme class >> baseSelectionColor [ 19 | ^ Color r: 97 g: 163 b: 225 range: 255 20 | ] 21 | 22 | { #category : #accessing } 23 | TWMUITheme class >> darkBaseColor [ 24 | ^ Color r: 180 g: 180 b: 180 range: 255 25 | ] 26 | 27 | { #category : #settings } 28 | TWMUITheme class >> defaultSettings [ 29 | "Answer the default settings for the theme." 30 | defaultSettings := nil. 31 | ^defaultSettings ifNil: [ 32 | self defaultSettings: self newDefaultSettings. 33 | defaultSettings] 34 | ] 35 | 36 | { #category : #private } 37 | TWMUITheme class >> importIcons: icons fromFolder: aString inClass: aClass category: aCategory [ 38 | icons 39 | do: [:each | 40 | | method form | 41 | form := PNGReadWriter formFromFileNamed: aString, '/', each , '.png'. 42 | method := each , Character cr asString , 43 | (aClass methodStart: each), 44 | form storeString, 45 | aClass methodEnd. 46 | aClass class compile: method classified: aCategory ]. 47 | aClass initialize 48 | ] 49 | 50 | { #category : #accessing } 51 | TWMUITheme class >> isAbstract [ 52 | ^ false 53 | ] 54 | 55 | { #category : #accessing } 56 | TWMUITheme class >> lightBaseColor [ 57 | ^ Color r: 200 g: 200 b: 200 range: 255 58 | ] 59 | 60 | { #category : #accessing } 61 | TWMUITheme class >> lightSelectionColor [ 62 | ^ Color r: 175 g: 213 b: 250 range: 255 63 | ] 64 | 65 | { #category : #settings } 66 | TWMUITheme class >> newDefaultSettings [ 67 | BalloonMorph setBalloonColorTo: self lightSelectionColor. 68 | ^super newDefaultSettings 69 | menuColor: self baseColor; 70 | menuTitleColor: self baseColor; 71 | windowColor: self baseColor; 72 | selectionColor: self lightSelectionColor; 73 | menuSelectionColor: self baseSelectionColor; 74 | progressBarColor: self baseColor; 75 | standardColorsOnly: false; 76 | autoSelectionColor: false; 77 | preferRoundCorner: false; 78 | flatMenu: true 79 | ] 80 | 81 | { #category : #settings } 82 | TWMUITheme class >> setPreferredWorldBackground [ 83 | "self setPreferredWorldBackground" 84 | "World color: ( 85 | (GradientFillStyle 86 | ramp: { 0.0 -> Color white. 1.0 -> Color gray}) 87 | origin: 50 @ 50; 88 | direction: 800@0; 89 | normal: 0@800; 90 | radial: true)" 91 | World color: Color white 92 | ] 93 | 94 | { #category : #accessing } 95 | TWMUITheme class >> themeName [ 96 | ^ 'TWM Theme' 97 | ] 98 | 99 | { #category : #accessing } 100 | TWMUITheme class >> veryLightSelectionColor [ 101 | ^ Color r: 218 g: 234 b: 250 range: 255 102 | ] 103 | 104 | { #category : #private } 105 | TWMUITheme >> baseColorFor: aMorph [ 106 | ^ self class baseColor 107 | "unfortunately, it looks like paneColor does not always return the wanted color" 108 | "aButton paneColorOrNil ifNil: [Color r: 200 g: 200 b: 200 range: 255]" 109 | ] 110 | 111 | { #category : #private } 112 | TWMUITheme >> baseDarkColorFor: aMorph [ 113 | ^ self class darkBaseColor 114 | ] 115 | 116 | { #category : #private } 117 | TWMUITheme >> basePassiveBackgroundColorFor: aMorph [ 118 | ^ self class basePassiveBackgroundColor 119 | ] 120 | 121 | { #category : #private } 122 | TWMUITheme >> baseSelectionColorFor: aMorph [ 123 | ^ self class baseSelectionColor 124 | ] 125 | 126 | { #category : #'border-styles-buttons' } 127 | TWMUITheme >> buttonCornerStyleIn: aThemedMorph [ 128 | "If asked, we only allow square corners" 129 | 130 | ^ #square 131 | ] 132 | 133 | { #category : #'label-styles' } 134 | TWMUITheme >> buttonLabelForText: aTextOrString [ 135 | "Answer the label to use for the given text." 136 | ^aTextOrString isString 137 | ifTrue: [(LabelMorph contents: aTextOrString) color: Color black] 138 | ifFalse: [super buttonLabelForText: aTextOrString] 139 | ] 140 | 141 | { #category : #defaults } 142 | TWMUITheme >> buttonMinHeight [ 143 | "Answer the minumum height of a button for this theme." 144 | 145 | ^24 146 | ] 147 | 148 | { #category : #defaults } 149 | TWMUITheme >> buttonMinWidth [ 150 | "Answer the minumum width of a button for this theme." 151 | 152 | ^24 153 | ] 154 | 155 | { #category : #'border-styles-buttons' } 156 | TWMUITheme >> buttonNormalBorderStyleFor: aButton [ 157 | "Return the normal button borderStyle for the given button." 158 | 159 | | outerColor innerColor | 160 | (aButton valueOfProperty: #noBorder ifAbsent: [false]) ifTrue: [ 161 | ^ SimpleBorder new width: 0; baseColor: Color transparent ]. 162 | outerColor := self baseDarkColorFor: aButton. 163 | ^SimpleBorder new 164 | width: 1; 165 | baseColor: outerColor 166 | ] 167 | 168 | { #category : #'fill-styles-buttons' } 169 | TWMUITheme >> buttonNormalFillStyleFor: aButton [ 170 | "Return the normal button fillStyle for the given button." 171 | 172 | |aColor| 173 | aColor := self buttonColorFor: aButton. 174 | ^(GradientFillStyle ramp: { 175 | 0.0->Color white. 176 | 0.1->aColor twiceLighter. 177 | 0.9->aColor darker. 178 | 1.0->aColor twiceDarker darker duller}) 179 | origin: aButton bounds origin; 180 | direction: 0 @ aButton height; 181 | radial: false 182 | ] 183 | 184 | { #category : #'fill-styles-buttons' } 185 | TWMUITheme >> buttonPressedFillStyleFor: aButton [ 186 | "Return the button pressed fillStyle for the given color." 187 | 188 | | aColor c | 189 | aColor := aButton colorToUse. 190 | c := aColor luminance > 0.3 191 | ifTrue: [ aColor blacker ] 192 | ifFalse: [ aColor whiter ]. 193 | ^ (GradientFillStyle 194 | ramp: 195 | {(0.0 -> c darker duller). 196 | (0.1 -> c darker). 197 | (0.9 -> c twiceLighter). 198 | (1.0 -> Color white)}) 199 | origin: aButton bounds origin; 200 | direction: 0 @ aButton height; 201 | radial: false 202 | ] 203 | 204 | { #category : #'border-styles-buttons' } 205 | TWMUITheme >> buttonSelectedBorderStyleFor: aButton [ 206 | ^ self buttonNormalBorderStyleFor: aButton 207 | ] 208 | 209 | { #category : #forms } 210 | TWMUITheme >> checkboxButtonNormalFillStyleFor: aCheckboxButton [ 211 | "Return the normal checkbox button fillStyle for the given checkbox button." 212 | 213 | ^(ImageFillStyle form: self checkboxForm) origin: aCheckboxButton topLeft 214 | ] 215 | 216 | { #category : #'fill-styles-buttons' } 217 | TWMUITheme >> checkboxButtonSelectedFillStyleFor: aCheckboxButton [ 218 | "Return the selected checkbox button fillStyle for the given checkbox button." 219 | 220 | ^(ImageFillStyle form: self checkboxSelectedForm) origin: aCheckboxButton topLeft 221 | ] 222 | 223 | { #category : #forms } 224 | TWMUITheme >> checkboxForm [ 225 | "Answer the form to use for a normal checkbox." 226 | 227 | ^self checkboxUnselectedForm 228 | ] 229 | 230 | { #category : #forms } 231 | TWMUITheme >> checkboxSelectedForm [ 232 | "Answer the form to use for a selected checkbox." 233 | 234 | ^ TWMUIThemeIcons checkboxSelectedForm 235 | ] 236 | 237 | { #category : #forms } 238 | TWMUITheme >> checkboxUnselectedForm [ 239 | "Answer the form to use for a selected checkbox." 240 | 241 | ^ TWMUIThemeIcons checkboxUnselectedForm 242 | ] 243 | 244 | { #category : #'border-styles' } 245 | TWMUITheme >> configureWindowBorderFor: aWindow [ 246 | | aStyle | 247 | aStyle := (SimpleBorder new) 248 | color: (Color black alpha: 0.5); 249 | width: 1. 250 | aWindow borderStyle: aStyle 251 | ] 252 | 253 | { #category : #'border-styles' } 254 | TWMUITheme >> configureWindowDropShadowFor: aWindow [ 255 | 256 | aWindow hasDropShadow: false 257 | ] 258 | 259 | { #category : #'label-styles' } 260 | TWMUITheme >> configureWindowLabelAreaFor: aWindow [ 261 | "Configure the label area for the given window." 262 | 263 | |padding| 264 | padding := 0. 265 | aWindow labelArea 266 | addMorphBack: (Morph new extent: aWindow class borderWidth @ 0). 267 | aWindow hasCloseBox ifTrue: [aWindow addCloseBox. padding := padding + 1]. 268 | aWindow hasCollapseBox ifTrue: [aWindow addCollapseBox. padding := padding + 1]. 269 | aWindow hasExpandBox ifTrue: [aWindow addExpandBox. padding := padding + 1]. 270 | aWindow hasMenuBox ifTrue: [padding := padding - 1]. 271 | aWindow labelArea 272 | addMorphBack: (Morph new extent: aWindow class borderWidth @ 0; hResizing: #spaceFill). 273 | aWindow basicLabel ifNotNil: [:label | aWindow labelArea addMorphBack: label; hResizing: #shrinkWrap]. 274 | aWindow labelArea 275 | addMorphBack: (Morph new extent: aWindow class borderWidth @ 0; hResizing: #spaceFill). 276 | padding > 0 ifTrue: [ 277 | aWindow labelArea 278 | addMorphBack: (Morph new extent: (aWindow boxExtent x * padding) @ 0)]. 279 | aWindow hasMenuBox ifTrue: [aWindow addMenuControl]. 280 | aWindow labelArea 281 | addMorphBack: (Morph new extent: aWindow class borderWidth @ 0) 282 | ] 283 | 284 | { #category : #'label-styles' } 285 | TWMUITheme >> createMenuBoxFor: aSystemWindow [ 286 | "Answer a button for the window menu." 287 | 288 | |form msb| 289 | form := self windowMenuForm. 290 | msb := MultistateButtonMorph new extent: form extent. 291 | msb activeEnabledNotOverUpFillStyle: (ImageFillStyle form: form). 292 | form := self windowMenuPassiveForm. 293 | msb extent: form extent. 294 | msb activeDisabledNotOverUpFillStyle: (ImageFillStyle form: form). 295 | msb passiveEnabledNotOverUpFillStyle: (ImageFillStyle form: form). 296 | msb passiveDisabledNotOverUpFillStyle: (ImageFillStyle form: form). 297 | form := self windowMenuForm. 298 | msb extent: form extent. 299 | msb 300 | activeEnabledOverUpFillStyle: (ImageFillStyle form: form); 301 | passiveEnabledOverUpFillStyle: (ImageFillStyle form: form). 302 | form := self windowMenuPassiveForm. 303 | msb 304 | extent: form extent; 305 | activeEnabledOverDownFillStyle: (ImageFillStyle form: form); 306 | passiveEnabledOverDownFillStyle: (ImageFillStyle form: form); 307 | addUpAction: [aSystemWindow offerWindowMenu]; 308 | setBalloonText: 'window menu' translated; 309 | extent: aSystemWindow boxExtent. 310 | ^msb 311 | ] 312 | 313 | { #category : #'fill-styles' } 314 | TWMUITheme >> dockingBarNormalFillStyleFor: aToolDockingBar [ 315 | ^ SolidFillStyle color: Color transparent 316 | ] 317 | 318 | { #category : #'fill-styles' } 319 | TWMUITheme >> dropListDisabledFillStyleFor: aDropList [ 320 | "Return the disabled fillStyle for the given drop list." 321 | 322 | ^ self textEditorDisabledFillStyleFor: aDropList 323 | ] 324 | 325 | { #category : #'border-styles' } 326 | TWMUITheme >> dropListNormalBorderStyleFor: aDropList [ 327 | "Return the normal borderStyle for the given drop list" 328 | 329 | ^ self buttonNormalBorderStyleFor: aDropList 330 | ] 331 | 332 | { #category : #'fill-styles' } 333 | TWMUITheme >> dropListNormalFillStyleFor: aDropList [ 334 | "Return the normal fillStyle for the given drop list." 335 | 336 | ^ SolidFillStyle color: Color white 337 | ] 338 | 339 | { #category : #'border-styles' } 340 | TWMUITheme >> groupPanelBorderStyleFor: aGroupPanel [ 341 | "Answer the normal border style for a group panel." 342 | 343 | ^ SimpleBorder new 344 | width: 1; 345 | baseColor: ((self baseColorFor: aGroupPanel)) 346 | ] 347 | 348 | { #category : #private } 349 | TWMUITheme >> lightColorFor: aMorph [ 350 | ^ self class lightBaseColor 351 | ] 352 | 353 | { #category : #private } 354 | TWMUITheme >> lightSelectionColorFor: aMorph [ 355 | ^ self class lightSelectionColor 356 | ] 357 | 358 | { #category : #'fill-styles' } 359 | TWMUITheme >> listDisabledFillStyleFor: aList [ 360 | "Return the disabled fillStyle for the given list." 361 | 362 | ^ self textEditorDisabledFillStyleFor: aList 363 | ] 364 | 365 | { #category : #forms } 366 | TWMUITheme >> menuPinForm [ 367 | "Answer the form to use for the pin button of a menu." 368 | 369 | ^ TWMUIThemeIcons menuPinForm 370 | ] 371 | 372 | { #category : #forms } 373 | TWMUITheme >> newCheckboxMarkerForm [ 374 | "Answer a new checkbox marker form." 375 | 376 | ^ TWMUIThemeIcons checkboxMarkerForm 377 | ] 378 | 379 | { #category : #'morph creation' } 380 | TWMUITheme >> newFocusIndicatorMorphFor: aMorph [ 381 | "Answer a new focus indicator for the given morph." 382 | 383 | |radius| 384 | radius := aMorph focusIndicatorCornerRadius. 385 | ^ BorderedMorph new 386 | fillStyle: Color transparent; 387 | borderStyle: (SimpleBorder new 388 | width: 1; 389 | baseColor: (self baseSelectionColorFor: aMorph)); 390 | bounds: aMorph focusBounds 391 | ] 392 | 393 | { #category : #forms } 394 | TWMUITheme >> newRadioButtonMarkerForm [ 395 | "Answer a new radio button marker form. We make it empty because we already have the selected radio button take care of the state." 396 | 397 | ^ TWMUIThemeIcons radioButtonMarkerForm 398 | ] 399 | 400 | { #category : #'initialize-release' } 401 | TWMUITheme >> newRadioMarkerForm [ 402 | "Answer a new checkbox marker form." 403 | 404 | ^Form extent: 12@12 depth: 32 405 | ] 406 | 407 | { #category : #forms } 408 | TWMUITheme >> newWindowCloseForm [ 409 | "Answer a new form for a window close box." 410 | 411 | ^ TWMUIThemeIcons windowCloseForm 412 | ] 413 | 414 | { #category : #forms } 415 | TWMUITheme >> newWindowCloseOverForm [ 416 | "Answer a new form for a window menu box." 417 | 418 | ^ self newWindowCloseForm 419 | ] 420 | 421 | { #category : #forms } 422 | TWMUITheme >> newWindowMaximizeForm [ 423 | "Answer a new form for a window maximize box." 424 | 425 | ^ TWMUIThemeIcons windowMaximizeForm 426 | ] 427 | 428 | { #category : #forms } 429 | TWMUITheme >> newWindowMaximizeOverForm [ 430 | "Answer a new form for a window menu box." 431 | 432 | ^ self newWindowMaximizeForm 433 | ] 434 | 435 | { #category : #forms } 436 | TWMUITheme >> newWindowMenuForm [ 437 | "Answer a new form for a window menu box." 438 | 439 | ^ TWMUIThemeIcons windowMenuForm 440 | ] 441 | 442 | { #category : #forms } 443 | TWMUITheme >> newWindowMenuPassiveForm [ 444 | "Answer a new form for a window menu box." 445 | 446 | ^ TWMUIThemeIcons windowMenuInactiveForm 447 | ] 448 | 449 | { #category : #forms } 450 | TWMUITheme >> newWindowMinimizeForm [ 451 | "Answer a new form for a window minimize box." 452 | 453 | ^ TWMUIThemeIcons windowMinimizeForm 454 | ] 455 | 456 | { #category : #forms } 457 | TWMUITheme >> newWindowMinimizeOverForm [ 458 | "Answer a new form for a window menu box." 459 | 460 | ^ self newWindowMinimizeForm 461 | ] 462 | 463 | { #category : #private } 464 | TWMUITheme >> normalFillStyleFor: aMorph height: anInteger [ 465 | "Return the normal button fillStyle for the given button." 466 | 467 | | baseColor | 468 | baseColor := self baseColorFor: aMorph. 469 | ^ self normalFillStyleWithBaseColor: baseColor for: aMorph height: anInteger 470 | 471 | ] 472 | 473 | { #category : #private } 474 | TWMUITheme >> normalFillStyleWithBaseColor: aColor for: aMorph height: anInteger [ 475 | 476 | | top bottom | 477 | top := aColor twiceLighter. 478 | bottom := aColor. 479 | ^(GradientFillStyle ramp: { 480 | 0.0->top. 481 | 0.7->bottom.}) 482 | origin: aMorph bounds origin; 483 | direction: 0 @ anInteger; 484 | radial: false 485 | ] 486 | 487 | { #category : #'border-styles' } 488 | TWMUITheme >> plainGroupPanelBorderStyleFor: aGroupPanel [ 489 | "Answer the normal border style for a plain group panel." 490 | 491 | ^SimpleBorder new 492 | width: 1; 493 | baseColor: Color transparent 494 | ] 495 | 496 | { #category : #'fill-styles' } 497 | TWMUITheme >> progressBarFillStyleFor: aProgressBar [ 498 | ^ self basePassiveBackgroundColorFor: aProgressBar 499 | ] 500 | 501 | { #category : #'fill-styles' } 502 | TWMUITheme >> progressBarProgressFillStyleFor: aProgressBar [ 503 | ^ (self lightSelectionColorFor: aProgressBar) 504 | ] 505 | 506 | { #category : #forms } 507 | TWMUITheme >> radioButtonForm [ 508 | "Answer the form to use for a normal radio button." 509 | 510 | ^ TWMUIThemeIcons radioButtonUnselectedForm 511 | ] 512 | 513 | { #category : #forms } 514 | TWMUITheme >> radioButtonNormalFillStyleFor: aRadioButton [ 515 | "Return the normal radio button fillStyle for the given button." 516 | 517 | ^(ImageFillStyle form: self radioButtonForm) origin: aRadioButton topLeft 518 | ] 519 | 520 | { #category : #forms } 521 | TWMUITheme >> radioButtonSelectedFillStyleFor: aRadioButton [ 522 | "Return the selected radio button fillStyle for the given button." 523 | 524 | ^(ImageFillStyle form: self radioButtonSelectedForm) origin: aRadioButton topLeft 525 | ] 526 | 527 | { #category : #forms } 528 | TWMUITheme >> radioButtonSelectedForm [ 529 | "Answer the form to use for a selected radio button." 530 | 531 | ^ TWMUIThemeIcons radioButtonSelectedForm 532 | ] 533 | 534 | { #category : #'fill-styles' } 535 | TWMUITheme >> resizerGripNormalFillStyleFor: aResizer [ 536 | "Return the normal fillStyle for the given resizer. 537 | For the moment, answer a transparent colour for no drawing, 538 | non transparent to draw as normal." 539 | 540 | ^Color transparent 541 | ] 542 | 543 | { #category : #'fill-styles-scrollbars' } 544 | TWMUITheme >> scrollbarNormalButtonFillStyleFor: aScrollbar [ 545 | "Return the normal scrollbar button fillStyle for the given scrollbar." 546 | 547 | ^ self scrollbarNormalThumbFillStyleFor: aScrollbar 548 | ] 549 | 550 | { #category : #'fill-styles-scrollbars' } 551 | TWMUITheme >> scrollbarNormalFillStyleFor: aScrollbar [ 552 | "Return the normal scrollbar fillStyle for the given scrollbar." 553 | 554 | ^ "(self glamorousBaseColorFor: aScrollbar) muchLighter" 555 | Color r: 245 g: 245 b: 245 range: 255 556 | ] 557 | 558 | { #category : #'fill-styles-scrollbars' } 559 | TWMUITheme >> scrollbarNormalThumbFillStyleFor: aScrollbar [ 560 | "Return the normal scrollbar fillStyle for the given scrollbar." 561 | 562 | ^ (self normalFillStyleWithBaseColor: aScrollbar paneColor for: aScrollbar height: aScrollbar height) 563 | direction: (aScrollbar bounds isWide 564 | ifTrue: [0 @ aScrollbar height] 565 | ifFalse: [aScrollbar width @ 0]) 566 | ] 567 | 568 | { #category : #'border-styles-scrollbars' } 569 | TWMUITheme >> scrollbarPagingAreaCornerStyleIn: aThemedMorph [ 570 | ^#square 571 | ] 572 | 573 | { #category : #'border-styles-scrollbars' } 574 | TWMUITheme >> scrollbarThumbCornerStyleIn: aThemedMorph [ 575 | ^#square 576 | ] 577 | 578 | { #category : #'fill-styles' } 579 | TWMUITheme >> separatorFillStyleFor: aSeparator [ 580 | "Return the separator fillStyle for the given separator." 581 | 582 | ^ SolidFillStyle color: (self baseColorFor: aSeparator) darker 583 | ] 584 | 585 | { #category : #'fill-styles' } 586 | TWMUITheme >> sliderDisabledFillStyleFor: aSlider [ 587 | "Return the disabled fillStyle for the given slider." 588 | 589 | ^ self textEditorDisabledFillStyleFor: aSlider 590 | ] 591 | 592 | { #category : #'fill-styles' } 593 | TWMUITheme >> splitterNormalFillStyleFor: aSplitter [ 594 | "Return the normal splitter fillStyle for the given splitter." 595 | 596 | ^ SolidFillStyle color: Color transparent 597 | ] 598 | 599 | { #category : #'fill-styles' } 600 | TWMUITheme >> splitterPressedFillStyleFor: aSplitter [ 601 | "Return the pressed splitter fillStyle for the given splitter." 602 | 603 | |aColor| 604 | aColor := self baseColorFor: aSplitter. 605 | ^ (GradientFillStyle ramp: {0.0->aColor lighter. 0.9-> aColor}) 606 | origin: aSplitter topLeft; 607 | direction: (aSplitter splitsTopAndBottom 608 | ifTrue: [0 @ aSplitter height] 609 | ifFalse: [aSplitter width @ 0]); 610 | radial: false 611 | ] 612 | 613 | { #category : #'basic-colors' } 614 | TWMUITheme >> subgroupColorFrom: paneColor [ 615 | "Answer the colour for a subgroup given the pane colour." 616 | 617 | ^ self lightColorFor: paneColor" self class baseColor" 618 | ] 619 | 620 | { #category : #'border-styles' } 621 | TWMUITheme >> tabLabelNormalBorderStyleFor: aTabLabel [ 622 | " ^SimpleBorder new 623 | width: 0; 624 | baseColor: (self buttonBaseColorFor: aTabLabel) darker 625 | " ^ self buttonNormalBorderStyleFor: aTabLabel 626 | ] 627 | 628 | { #category : #'border-styles' } 629 | TWMUITheme >> tabLabelNormalFillStyleFor: aTabLabel [ 630 | ^ self baseColorFor: aTabLabel 631 | ] 632 | 633 | { #category : #'border-styles' } 634 | TWMUITheme >> tabLabelSelectedFillStyleFor: aTabLabel [ 635 | ^ self baseSelectionColorFor: aTabLabel 636 | ] 637 | 638 | { #category : #'border-styles' } 639 | TWMUITheme >> tabPanelBorderStyleFor: aTabGroup [ 640 | ^ StandardTabPanelBorder new 641 | width: 1; 642 | baseColor: ((self baseDarkColorFor: aTabGroup)); 643 | tabSelector: aTabGroup tabSelectorMorph 644 | ] 645 | 646 | { #category : #'basic-colors' } 647 | TWMUITheme >> taskbarButtonLabelColorFor: aButton [ 648 | "Answer the colour for the label of the given taskbar button." 649 | 650 | ^aButton model 651 | ifNil: [super taskbarButtonLabelColorFor: aButton] 652 | ifNotNil: [:win | 653 | win isActive 654 | ifTrue: [Color black] 655 | ifFalse: [Color gray darker]] 656 | ] 657 | 658 | { #category : #'border-styles' } 659 | TWMUITheme >> taskbarThumbnailCornerStyleFor: aMorph [ 660 | "Answer the corner style for the taskbar thumbnail/tasklist." 661 | 662 | ^#square 663 | ] 664 | 665 | { #category : #'border-styles' } 666 | TWMUITheme >> taskbarThumbnailNormalBorderStyleFor: aWindow [ 667 | ^ self buttonNormalBorderStyleFor: aWindow 668 | ] 669 | 670 | { #category : #'fill-styles' } 671 | TWMUITheme >> textEditorDisabledFillStyleFor: aTextEditor [ 672 | "Return the disabled fillStyle for the given text editor." 673 | 674 | ^self basePassiveBackgroundColorFor: aTextEditor 675 | ] 676 | 677 | { #category : #'border-styles' } 678 | TWMUITheme >> textEditorNormalBorderStyleFor: aTextEditor [ 679 | "Return the normal text editor borderStyle for the given text editor." 680 | 681 | ^self buttonNormalBorderStyleFor: aTextEditor 682 | ] 683 | 684 | { #category : #scrollbars } 685 | TWMUITheme >> verticesForSimpleArrow: aRectangle [ 686 | | vertices | 687 | vertices := OrderedCollection new. 688 | "" 689 | vertices add: aRectangle bottomLeft. 690 | vertices add: aRectangle center x @ (aRectangle top + (aRectangle width / 8)). 691 | vertices add: aRectangle bottomRight. 692 | vertices add: aRectangle bottomRight + (0@0.01). 693 | "" 694 | ^ vertices 695 | ] 696 | 697 | { #category : #forms } 698 | TWMUITheme >> windowClosePassiveForm [ 699 | "Answer the form to use for passive (background) window close buttons" 700 | 701 | ^ TWMUIThemeIcons windowCloseInactiveForm 702 | ] 703 | 704 | { #category : #forms } 705 | TWMUITheme >> windowMaximizePassiveForm [ 706 | "Answer the form to use for passive (background) window maximize/restore buttons" 707 | 708 | ^ TWMUIThemeIcons windowMaximizeInactiveForm 709 | ] 710 | 711 | { #category : #'label-styles' } 712 | TWMUITheme >> windowMenuPassiveForm [ 713 | "Answer the form to use for passive (background) window menu buttons" 714 | 715 | ^self newWindowMenuPassiveForm 716 | ] 717 | 718 | { #category : #forms } 719 | TWMUITheme >> windowMinimizePassiveForm [ 720 | "Answer the form to use for passive (background) window minimize buttons" 721 | 722 | ^ TWMUIThemeIcons windowMinimizeInactiveForm 723 | ] 724 | --------------------------------------------------------------------------------