diff --git a/data/ui/options/misc_d.png b/data/ui/options/misc_d.png new file mode 100644 index 00000000..d1a6392e Binary files /dev/null and b/data/ui/options/misc_d.png differ diff --git a/data/ui/options/misc_h.png b/data/ui/options/misc_h.png new file mode 100644 index 00000000..7573b667 Binary files /dev/null and b/data/ui/options/misc_h.png differ diff --git a/data/ui/options/misc_i.png b/data/ui/options/misc_i.png new file mode 100644 index 00000000..4eeea84f Binary files /dev/null and b/data/ui/options/misc_i.png differ diff --git a/data/ui/options/misc_n.png b/data/ui/options/misc_n.png new file mode 100644 index 00000000..df5341ac Binary files /dev/null and b/data/ui/options/misc_n.png differ diff --git a/src/gui/GuiScrollCtrl.hx b/src/gui/GuiScrollCtrl.hx index 32fa399d..00b93aa1 100644 --- a/src/gui/GuiScrollCtrl.hx +++ b/src/gui/GuiScrollCtrl.hx @@ -246,59 +246,59 @@ class GuiScrollCtrl extends GuiControl { } public override function onMousePress(mouseState:MouseState) { - // if (Util.isTouchDevice()) { - this.pressed = true; - this.dirty = true; - this.updateScrollVisual(); - this.prevMousePos = mouseState.position; - this.scrollVelocity = 0; - this.momentumActive = false; - this.lastMoveStamp = Timer.stamp(); - // } + if (Util.isTouchDevice()) { + this.pressed = true; + this.dirty = true; + this.updateScrollVisual(); + this.prevMousePos = mouseState.position; + this.scrollVelocity = 0; + this.momentumActive = false; + this.lastMoveStamp = Timer.stamp(); + } } public override function onMouseRelease(mouseState:MouseState) { - // if (Util.isTouchDevice()) { - this.pressed = false; - this.dirty = true; - deltaY = 0; - this.updateScrollVisual(); - this.momentumActive = Math.abs(scrollVelocity) > 0.01; - this.lastMoveStamp = 0; - // } + if (Util.isTouchDevice()) { + this.pressed = false; + this.dirty = true; + deltaY = 0; + this.updateScrollVisual(); + this.momentumActive = Math.abs(scrollVelocity) > 0.01; + this.lastMoveStamp = 0; + } } public override function onMouseMove(mouseState:MouseState) { - // if (Util.isTouchDevice()) { - super.onMouseMove(mouseState); - if (this.pressed) { - var renderRect = this.getRenderRectangle(); - var scrollExtentY = renderRect.extent.y; - var dy = (mouseState.position.y - this.prevMousePos.y) / ((maxScrollY * Settings.uiScale) / scrollExtentY); - deltaY = -dy; - this.scrollY -= dy; - this.prevMousePos = mouseState.position; - var now = Timer.stamp(); - if (lastMoveStamp > 0) { - var dt = now - lastMoveStamp; - if (dt > 0) - scrollVelocity = -dy / dt; + if (Util.isTouchDevice()) { + super.onMouseMove(mouseState); + if (this.pressed) { + var renderRect = this.getRenderRectangle(); + var scrollExtentY = renderRect.extent.y; + var dy = (mouseState.position.y - this.prevMousePos.y) / ((maxScrollY * Settings.uiScale) / scrollExtentY); + deltaY = -dy; + this.scrollY -= dy; + this.prevMousePos = mouseState.position; + var now = Timer.stamp(); + if (lastMoveStamp > 0) { + var dt = now - lastMoveStamp; + if (dt > 0) + scrollVelocity = -dy / dt; + } + lastMoveStamp = now; + momentumActive = false; + this.updateScrollVisual(); } - lastMoveStamp = now; - momentumActive = false; - this.updateScrollVisual(); } - // } } public override function onMouseLeave(mouseState:MouseState) { - // if (Util.isTouchDevice()) { - this.pressed = false; - this.dirty = true; - this.updateScrollVisual(); - this.momentumActive = Math.abs(scrollVelocity) > 0.01; - this.lastMoveStamp = 0; - // } + if (Util.isTouchDevice()) { + this.pressed = false; + this.dirty = true; + this.updateScrollVisual(); + this.momentumActive = Math.abs(scrollVelocity) > 0.01; + this.lastMoveStamp = 0; + } } public override function update(dt:Float, mouseState:MouseState) { diff --git a/src/gui/OptionsDlg.hx b/src/gui/OptionsDlg.hx index 26153071..eb4bc39d 100644 --- a/src/gui/OptionsDlg.hx +++ b/src/gui/OptionsDlg.hx @@ -1,5 +1,6 @@ package gui; +import haxe.DynamicAccess; import hxd.BitmapData; import h2d.filter.DropShadow; import h2d.Text; @@ -70,10 +71,10 @@ class OptionsDlg extends GuiImage { hotkeysBtn.extent = new Vector(134, 65); window.addChild(hotkeysBtn); - var onlineBtn = new GuiImage(ResourceLoader.getResource("data/ui/options/online_i.png", ResourceLoader.getImage, this.imageResources).toTile()); - onlineBtn.position = new Vector(548, 19); - onlineBtn.extent = new Vector(134, 65); - window.addChild(onlineBtn); + var miscBtn = new GuiButton(loadButtonImages('data/ui/options/misc')); + miscBtn.position = new Vector(548, 19); + miscBtn.extent = new Vector(134, 65); + window.addChild(miscBtn); var generalPanel:GuiScrollCtrl = null; @@ -114,6 +115,10 @@ class OptionsDlg extends GuiImage { hotkeysPanel.position = new Vector(30, 88); hotkeysPanel.extent = new Vector(726, 394); + var miscPanel = new GuiControl(); + miscPanel.position = new Vector(30, 88); + miscPanel.extent = new Vector(726, 394); + var markerFelt32fontdata = ResourceLoader.getFileEntry("data/font/MarkerFelt.fnt"); var markerFelt32b = new BitmapFont(markerFelt32fontdata.entry); @:privateAccess markerFelt32b.loader = ResourceLoader.loader; @@ -470,6 +475,31 @@ class OptionsDlg extends GuiImage { parent.addChild(remapBtn); } + function makeButton(text:String, yPos:Int, buttonText:String, pressedAction:() -> Void, parent:GuiControl, right:Bool = false) { + var textObj = new GuiText(markerFelt32); + textObj.position = new Vector(right ? 368 : 5, yPos); + textObj.extent = new Vector(212, 14); + textObj.text.text = text; + textObj.text.textColor = 0xFFFFFF; + textObj.text.dropShadow = { + dx: 1 * Settings.uiScale, + dy: 1 * Settings.uiScale, + alpha: 0.5, + color: 0 + }; + parent.addChild(textObj); + + var btn = new GuiButtonText(loadButtonImages("data/ui/options/bind"), markerFelt24); + btn.position = new Vector(right ? 363 + 203 : 203, yPos - 3); + btn.txtCtrl.text.text = buttonText; + btn.setExtent(new Vector(152, 49)); + btn.pressedAction = (sender) -> { + pressedAction(); + } + + parent.addChild(btn); + } + if (Util.isTouchDevice()) { var textObj = new GuiText(markerFelt32); textObj.position = new Vector(5, 38); @@ -540,10 +570,85 @@ class OptionsDlg extends GuiImage { hotkeysPanel, true); } + // MISC PANEL + makeButton("Import Progress:", 38, "Import", () -> { + hxd.File.browse((sel) -> { + sel.load((data) -> { + try { + // convert to string + var jsonStr = data.toString(); + // parse JSON + var json = haxe.Json.parse(jsonStr); + + var highScoreData:DynamicAccess> = json.highScores; + for (key => value in highScoreData) { + Settings.highScores.set(key, value); + } + var easterEggData:DynamicAccess = json.easterEggs; + if (easterEggData != null) { + for (key => value in easterEggData) { + Settings.easterEggs.set(key, value); + } + } + MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Progress data imported successfully!")); + Settings.save(); + } catch (e) { + MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("Failed to import progress data: " + e.message)); + } + }); + }, { + title: "Select a progress file to import", + fileTypes: [ + {name: "JSON files", extensions: ["json"]}, + {name: "All files", extensions: ["*"]} + ], + }); + }, miscPanel); + makeButton("Export Progress:", 38, "Export", () -> { + #if sys + #if MACOS_BUNDLE + // open the finder to that folder + Sys.command('open "${Settings.settingsDir}"'); + #else + // Just open the folder in the explorer.exe + Sys.command('explorer.exe "${Settings.settingsDir}"'); + #end + MarbleGame.canvas.pushDialog(new MessageBoxOkDlg("The settings.json file contains your progress data. You can copy it to another device or share it with others.")); + #end + #if js + // Serialize Settings to JSON + var localStorage = js.Browser.getLocalStorage(); + if (localStorage != null) { + var settingsData = localStorage.getItem("MBHaxeSettings"); + if (settingsData != null) { + // Download this + var replayBytes = settingsData; + var blob = new js.html.Blob([haxe.io.Bytes.ofString(replayBytes).getData()], { + type: 'application/octet-stream' + }); + var url = js.html.URL.createObjectURL(blob); + var fname = 'settings.json'; + var element = js.Browser.document.createElement('a'); + element.setAttribute('href', url); + element.setAttribute('download', fname); + + element.style.display = 'none'; + js.Browser.document.body.appendChild(element); + + element.click(); + + js.Browser.document.body.removeChild(element); + js.html.URL.revokeObjectURL(url); + } + } + #end + }, miscPanel, true); + generalBtn.pressedAction = (e) -> { if (currentTab != "general") { currentTab = "general"; - hotkeysPanel.parent.removeChild(hotkeysPanel); + hotkeysPanel.parent?.removeChild(hotkeysPanel); + miscPanel.parent?.removeChild(miscPanel); generalPanel.scrollY = 0; window.addChild(generalPanel); MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh @@ -553,12 +658,23 @@ class OptionsDlg extends GuiImage { hotkeysBtn.pressedAction = (e) -> { if (currentTab != "hotkeys") { currentTab = "hotkeys"; - generalPanel.parent.removeChild(generalPanel); + generalPanel.parent?.removeChild(generalPanel); + miscPanel.parent?.removeChild(miscPanel); window.addChild(hotkeysPanel); MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh } }; + miscBtn.pressedAction = (e) -> { + if (currentTab != "misc") { + currentTab = "misc"; + generalPanel.parent?.removeChild(generalPanel); + hotkeysPanel.parent?.removeChild(hotkeysPanel); + window.addChild(miscPanel); + MarbleGame.canvas.render(MarbleGame.canvas.scene2d); // Force refresh + } + }; + // // Touch Controls buttons??? // if (Util.isTouchDevice()) { // var touchControlsTxt = new GuiText(domcasual24);