Files
kiss-vscode/projects/nat-flixel-desktop-playground/source/PlayState.kiss

268 lines
10 KiB
Plaintext

(loadFrom "nat-archive-tool" "src/nat/Lib.kiss")
// TODO store a map of Entry IDs -> EntrySprites.
// TODO handleChanges() will need to kill every changed Entry's sprite and make a new one
// TODO make the EntrySprite constructor assign the entry a serialized position component
// maybe by writing a Map<String, Point> positions component so there can be multiple?
(method &override :Void create []
(super.create)
(FlxG.plugins.add (new FlxMouseControl))
(set FlxG.sound.muteKeys null)
// TODO find a better way to pass the archiveDir to a HaxeFlixel game
(let [archiveDir
(or (Sys.getEnv "NAT_DIR") (throw "NAT_DIR environment variable must be set"))
archive
(new Archive archiveDir)]
(set this.archive archive)
(set controller
(new ArchiveController
archive
this)))
(prop &mut :FlxGroup uiGroup (new FlxGroup))
(add uiGroup)
(prop :FlxTypedGroup<EntrySprite> entryGroup (new FlxTypedGroup<EntrySprite>))
(add entryGroup)
(prop uiCamera (new FlxCamera 0 0 FlxG.width FlxG.height))
(set uiCamera.bgColor FlxColor.TRANSPARENT)
(FlxG.cameras.add uiCamera false)
(set uiGroup.cameras [uiCamera])
(prop mouseDragCamera (new FlxCamera 0 0 FlxG.width FlxG.height))
(set mouseDragCamera.bgColor FlxColor.TRANSPARENT)
(FlxG.cameras.add mouseDragCamera false)
(prop mouseDragSprite (new FlxSprite 0 0))
(prop &mut :FlxPoint mouseDown null)
(mouseDragSprite.makeGraphic FlxG.width FlxG.height FlxColor.TRANSPARENT)
(set mouseDragSprite.cameras [mouseDragCamera])
(add mouseDragSprite)
(FlxMouseEventManager.add mouseDragSprite
// mouseDown
->s {
(set mouseDown (FlxG.mouse.getScreenPosition))
(controller.SelectEntries [])
(entryGroup.forEach
->entrySprite
(when (.containsPoint (entrySprite.getScreenBounds) (FlxG.mouse.getScreenPosition))
(controller.SelectEntry entrySprite.e)))
}
// mouseUp
->s {
(set mouseDown null)
(mouseDragSprite.makeGraphic FlxG.width FlxG.height FlxColor.TRANSPARENT true)
}
// mouseOver
->s {}
// mouseOut
->s {}
true
true
false)
(FlxMouseEventManager.setMouseMoveCallback mouseDragSprite
->s (when mouseDown (unless FlxMouseControl.isDragging
// draw the selection rectangle
(mouseDragSprite.makeGraphic FlxG.width FlxG.height FlxColor.TRANSPARENT true)
(let [curPos (FlxG.mouse.getScreenPosition)
x1 (min curPos.x mouseDown.x)
y1 (min curPos.y mouseDown.y)
x2 (max curPos.x mouseDown.x)
y2 (max curPos.y mouseDown.y)
selectWidth (- x2 x1)
selectHeight (- y2 y1)
rectangle (new FlxRect x1 y1 selectWidth selectHeight)]
(mouseDragSprite.drawRect x1 y1 selectWidth selectHeight FlxColor.TRANSPARENT (object color FlxColor.LIME))
// Handle entry selection
(entryGroup.forEach ->entrySprite
(let [overlaps (rectangle.overlaps (entrySprite.getScreenBounds))]
(when !(= overlaps (controller.isSelected entrySprite.e))
(controller.ToggleSelectEntry entrySprite.e))))))))
// make text-only sprites for entries that have no images:
(archive.addSystem (new TextSpriteSystem))
// make interactible sprites for entries that have images
// TODO allow configuring the tags at runtime and erasing/re-creating sprites later
// TODO allow using other position keys and erasing/re-creating sprites later
(prop &mut :EntrySpriteSystem spriteSystem)
(set spriteSystem (new EntrySpriteSystem "!done" "Playground-MAIN" this controller))
(archive.addSystem spriteSystem)
(archive.processSystems this))
(method &override :Void update [:Float elapsed]
(super.update elapsed)
(when FlxG.keys.justPressed.ESCAPE
(Sys.exit 0))
// Press ENTER to type a command to run
(when (and !textInput FlxG.keys.justPressed.ENTER)
(typeCommand))
(when (and textInput !textInput.alive)
(set textInput null))
// Press ESCAPE to clear the UI and cancel any input
(when FlxG.keys.justPressed.ESCAPE
(clearUI))
// Scroll the UI with the mouse:
(var UI_SCROLL_FACTOR 2)
(+= uiCamera.y (* FlxG.mouse.wheel UI_SCROLL_FACTOR))
// TODO allow changing the a scroll factor
// Control the UI camera with WASD, and the playground camera with arrow keys:
(var KEYBOARD_SCROLL_SPEED 200)
(FlxG.camera.updateKeyControl
elapsed
KEYBOARD_SCROLL_SPEED
->{FlxG.keys.pressed.LEFT}
->{FlxG.keys.pressed.RIGHT}
->{FlxG.keys.pressed.UP}
->{FlxG.keys.pressed.DOWN})
(FlxG.camera.updateMouseBorderControl elapsed KEYBOARD_SCROLL_SPEED 0.15)
(FlxG.camera.updateScrollWheelZoom elapsed 1)
// don't move the ui camera before ui has been placed -- new UI elements could appear offscreen
(when (> uiGroup.length 0)
(unless (and textInput textInput.hasFocus)
(uiCamera.updateKeyControl
elapsed
KEYBOARD_SCROLL_SPEED
// TODO support dvorak
->{FlxG.keys.pressed.A}
->{FlxG.keys.pressed.D}
->{FlxG.keys.pressed.W}
->{FlxG.keys.pressed.S}))))
(method :Void typeCommand []
(enterText
"command to run:"
->commandName (controller.tryRunCommand commandName)
Math.POSITIVE_INFINITY))
(prop &mut :ArchiveController controller)
(prop &mut :Archive archive)
(prop &mut :FlxText textInputLabel null)
(prop &mut :FlxInputText textInput null)
(method :Void enterText [prompt resolve maxLength]
(set textInputLabel (new FlxText 0 0 300 prompt))
(showUI textInputLabel)
(set textInput (new FlxInputText 0 0 300 ""))
(set textInput.hasFocus true)
(set textInput.callback
->:Void [text action]
// Super weird that this check is necessary
(when textInput
(case [text action]
([text FlxInputText.ENTER_ACTION]
(set textInput.callback null)
(hideUI textInput)
// This part is hacky...
(set lastUI textInputLabel)
(hideUI textInputLabel)
(resolve text))
//([_ FlxInputText.])
(otherwise {}))))
(showUI textInput))
(method :Void enterNumber [prompt resolve min max &opt inStepsOf]
(enterText prompt
->:Void [numberStr]
(let [number
(try (Std.parseFloat numberStr)
(catch [e]
(reportError "Not a number: $numberStr")
(return)))]
(resolve number))
Math.POSITIVE_INFINITY))
(method :Void chooseEntry [prompt :Archive archive resolve]
(resolve null))
(method :Void chooseEntries [prompt archive resolve min max]
(_chooseEntries prompt archive resolve min max []))
// TODO is it possible to resolve with less than max?
(method :Void _chooseEntries [prompt archive resolve min max :Array<Entry> collectedEntries]
(let [&mut :Void->Void chooseNextEntry
null
_chooseNextEntry
->:Void {(chooseEntry
prompt
archive
->:Void e {(collectedEntries.push e)
// If the maximum is reached, return it
(if (= max collectedEntries.length)
(resolve collectedEntries)
// Otherwise, recurse
(chooseNextEntry))})}]
(set chooseNextEntry _chooseNextEntry)
(_chooseNextEntry)))
(method handleChanges [:Archive archive :ChangeSet changeSet]
(doFor e changeSet
// process the WikipediaImageSystem and run spriteSystem process on newly created entries that get one
(archive.processSystems)
// Do a second loop through the systems, so Playground systems that trigger Core systems have their effects processed
(archive.processSystems)
// Entries whose data changed to remove them from the sprite pool will already have been removed
// by refreshEntry()
(when (spriteSystem.entries.exists e.id)
// refresh the sprites for entries that changed data but still should have sprites
(when (spriteSystem.sprites.exists e.id)
(spriteSystem.onRemoveEntry archive e))
(spriteSystem.processEntry archive e))))
(prop &mut :Int uiY 0)
(prop &mut :FlxSprite lastUI null)
(method :Void showUI [:FlxSprite ui]
(set ui.y uiY)
(uiGroup.add ui)
(set lastUI ui)
(+= uiY ui.height)
(when (> uiY FlxG.height) (+= uiCamera.scroll.y ui.height)))
(method :Void hideUI [:FlxSprite ui]
(uiGroup.remove ui)
(ui.kill)
(when (= lastUI ui) (-= uiY ui.height)))
(method :Void displayMessage [:String message]
(let [messageText (new FlxText 0 0 0 (message.replace "\n" "|"))]
(showUI messageText)))
(method :Void clearUI []
(when textInput
(set textInput.callback null))
(uiGroup.kill)
(set uiGroup (new FlxGroup))
(set uiGroup.cameras [uiCamera])
(add uiGroup)
(set uiY 0)
(set uiCamera.scroll.x 0)
(set uiCamera.scroll.y 0))
(method :Void reportError [:String error]
(let [text (new FlxText 0 0 0 (error.replace "\n" "|"))]
(text.setFormat null 8 FlxColor.RED)
(showUI text)))
(method :Void onSelectionChanged [:Array<Entry> selectedEntries :Array<Entry> lastSelectedEntries]
(doFor e (selectedEntries.concat lastSelectedEntries)
(whenLet [sprite (dictGet spriteSystem.sprites e.id)]
(sprite.updateColor))))