<commit_before>/*
 * FXGL - JavaFX Game Library. The MIT License (MIT).
 * Copyright (c) AlmasB (<EMAIL>).
 * See LICENSE for details.
 */

package com.almasb.fxgl.app

import com.almasb.fxgl.io.UIDialogHandler
import com.almasb.fxgl.scene.FXGLScene
import com.almasb.fxgl.util.EmptyRunnable
import javafx.beans.property.DoubleProperty
import javafx.scene.Node
import javafx.scene.control.Button
import javafx.scene.effect.BoxBlur
import javafx.scene.effect.Effect
import javafx.scene.layout.Background
import javafx.scene.layout.BackgroundFill
import javafx.scene.layout.Pane
import javafx.scene.paint.Color
import jfxtras.scene.control.window.Window
import java.util.*
import java.util.function.Consumer
import java.util.function.Predicate

/**
 *
 *
 * @author <NAME> (<EMAIL>)
 */
object DialogSubState : SubState() {

    private val window = Window()
    private val dialogFactory = FXGL.getSettings().dialogFactory

    private val states = ArrayDeque<DialogData>()

    init {
        val width = FXGL.getSettings().width.toDouble()
        val height = FXGL.getSettings().height.toDouble()

        (view as Pane).setPrefSize(width, height)
        (view as Pane).background = Background(BackgroundFill(Color.rgb(127, 127, 123, 0.5), null, null))

        window.isResizableWindow = false
        window.isMovable = false
        window.background = Background(BackgroundFill(Color.BLACK, null, null))

        window.layoutXProperty().bind(window.widthProperty().divide(2).negate().add(width / 2))
        window.layoutYProperty().bind(window.heightProperty().divide(2).negate().add(height / 2))

        children.add(window)

        // this is a workaround to avoid users traversing "through" the dialog to underlying nodes
        initTraversalPolicy()
    }

    @Suppress("DEPRECATION")
    private fun initTraversalPolicy() {
//        (view as Pane).impl_traversalEngine = ParentTraversalEngine(view as Pane, object : Algorithm {
//            override fun select(owner: Node, dir: Direction, context: TraversalContext): Node {
//                return window
//            }
//
//            override fun selectFirst(context: TraversalContext): Node {
//                return window
//            }
//
//            override fun selectLast(context: TraversalContext): Node {
//                return window
//            }
//        })
    }

    val isShowing: Boolean
        get() = view.scene != null

    /**
     * Replaces all content of the internal window by given node.
     * Creates an appropriate size rectangle box around the node
     * to serve as background.
     *
     * @param title window title
     * @param content content pane
     */
    private fun show(title: String, content: Pane) {
        if (isShowing) {
            // dialog was requested while being shown so remember state
            states.push(DialogData(window.title, window.contentPane))
        }

        window.title = title
        window.contentPane = content

        show()
    }

    private fun show() {
        if (!isShowing) {
            openInScene(FXGL.getApp().scene)

            view.requestFocus()
        }
    }

    private fun close() {
        if (states.isEmpty()) {
            closeInScene(FXGL.getApp().scene)
        } else {
            val data = states.pop()
            window.title = data.title
            window.contentPane = data.contentPane
        }
    }

    private val bgBlur = BoxBlur(5.0, 5.0, 3)
    private var savedEffect: Effect? = null

    private fun openInScene(scene: FXGLScene) {
        savedEffect = scene.effect
        scene.effect = bgBlur

        FXGL.getApp().stateMachine.pushState(this)
    }

    private fun closeInScene(scene: FXGLScene) {
        scene.effect = savedEffect

        FXGL.getApp().stateMachine.popState()
    }

    internal fun showMessageBox(message: String, callback: Runnable) {
        val dialog = dialogFactory.messageDialog(message, {
            close()
            callback.run()
        })

        show("Message", dialog)
    }

    internal fun showConfirmationBox(message: String, resultCallback: Consumer<Boolean>) {
        val dialog = dialogFactory.confirmationDialog(message, {
            close()
            resultCallback.accept(it)
        })

        show("Confirm", dialog)
    }

    internal fun showInputBox(message: String, filter: Predicate<String>, resultCallback: Consumer<String>) {
        val dialog = dialogFactory.inputDialog(message, filter, Consumer {
            close()
            resultCallback.accept(it)
        })

        show("Input", dialog)
    }

    internal fun showInputBoxWithCancel(message: String, filter: Predicate<String>, resultCallback: Consumer<String>) {
        val dialog = dialogFactory.inputDialogWithCancel(message, filter, Consumer {
            close()
            resultCallback.accept(it)
        })

        show("Input", dialog)
    }

    internal fun showErrorBox(error: Throwable) {
        showErrorBox(error, EmptyRunnable)
    }

    internal fun showErrorBox(error: Throwable, callback: Runnable) {
        val dialog = dialogFactory.errorDialog(error, {
            close()
            callback.run()
        })

        show("Error", dialog)
    }

    internal fun showErrorBox(errorMessage: String, callback: Runnable) {
        val dialog = dialogFactory.errorDialog(errorMessage, {
            close()
            callback.run()
        })

        show("Error", dialog)
    }

    internal fun showBox(message: String, content: Node, vararg buttons: Button) {
        val dialog = dialogFactory.customDialog(message, content, Runnable { close() }, *buttons)

        show("Dialog", dialog)
    }

    internal fun showProgressBox(message: String): UIDialogHandler {
        val dialog = dialogFactory.progressDialogIndeterminate(message, {
            close()
        })

        show("Progress", dialog)

        return object : UIDialogHandler {
            override fun show() {
                // no-op
            }

            override fun dismiss() {
                close()
            }
        }
    }

    internal fun showProgressBox(message: String, observable: DoubleProperty, callback: Runnable) {
        val dialog = dialogFactory.progressDialog(message, observable, {
            close()
            callback.run()
        })

        show("Progress", dialog)
    }

    private class DialogData internal constructor(internal var title: String, internal var contentPane: Pane)
}<commit_msg>fix for dialog traversal, closes #385<commit_after>/*
 * FXGL - JavaFX Game Library. The MIT License (MIT).
 * Copyright (c) AlmasB (<EMAIL>).
 * See LICENSE for details.
 */

package com.almasb.fxgl.app

import com.almasb.fxgl.io.UIDialogHandler
import com.almasb.fxgl.scene.FXGLScene
import com.almasb.fxgl.util.EmptyRunnable
import javafx.beans.property.DoubleProperty
import javafx.scene.Node
import javafx.scene.control.Button
import javafx.scene.effect.BoxBlur
import javafx.scene.effect.Effect
import javafx.scene.input.KeyCode
import javafx.scene.input.KeyEvent
import javafx.scene.layout.Background
import javafx.scene.layout.BackgroundFill
import javafx.scene.layout.Pane
import javafx.scene.paint.Color
import jfxtras.scene.control.window.Window
import java.util.*
import java.util.function.Consumer
import java.util.function.Predicate

/**
 *
 *
 * @author <NAME> (<EMAIL>)
 */
object DialogSubState : SubState() {

    private val window = Window()
    private val dialogFactory = FXGL.getSettings().dialogFactory

    private val states = ArrayDeque<DialogData>()

    init {
        val width = FXGL.getSettings().width.toDouble()
        val height = FXGL.getSettings().height.toDouble()

        (view as Pane).setPrefSize(width, height)
        (view as Pane).background = Background(BackgroundFill(Color.rgb(127, 127, 123, 0.5), null, null))

        window.isResizableWindow = false
        window.isMovable = false
        window.background = Background(BackgroundFill(Color.BLACK, null, null))

        window.layoutXProperty().bind(window.widthProperty().divide(2).negate().add(width / 2))
        window.layoutYProperty().bind(window.heightProperty().divide(2).negate().add(height / 2))

        children.add(window)

        // keep traversal input within this node
        initTraversalPolicy()
    }

    private fun initTraversalPolicy() {
        window.addEventFilter(KeyEvent.KEY_PRESSED, {
            if (it.code == KeyCode.TAB
                    || it.code == KeyCode.UP
                    || it.code == KeyCode.DOWN
                    || it.code == KeyCode.LEFT
                    || it.code == KeyCode.RIGHT) {
                it.consume()
            }
        })
    }

    val isShowing: Boolean
        get() = view.scene != null

    /**
     * Replaces all content of the internal window by given node.
     * Creates an appropriate size rectangle box around the node
     * to serve as background.
     *
     * @param title window title
     * @param content content pane
     */
    private fun show(title: String, content: Pane) {
        if (isShowing) {
            // dialog was requested while being shown so remember state
            states.push(DialogData(window.title, window.contentPane))
        }

        window.title = title
        window.contentPane = content

        show()
    }

    private fun show() {
        if (!isShowing) {
            openInScene(FXGL.getApp().scene)

            view.requestFocus()
        }
    }

    private fun close() {
        if (states.isEmpty()) {
            closeInScene(FXGL.getApp().scene)
        } else {
            val data = states.pop()
            window.title = data.title
            window.contentPane = data.contentPane
        }
    }

    private val bgBlur = BoxBlur(5.0, 5.0, 3)
    private var savedEffect: Effect? = null

    private fun openInScene(scene: FXGLScene) {
        savedEffect = scene.effect
        scene.effect = bgBlur

        FXGL.getApp().stateMachine.pushState(this)
    }

    private fun closeInScene(scene: FXGLScene) {
        scene.effect = savedEffect

        FXGL.getApp().stateMachine.popState()
    }

    internal fun showMessageBox(message: String, callback: Runnable) {
        val dialog = dialogFactory.messageDialog(message, {
            close()
            callback.run()
        })

        show("Message", dialog)
    }

    internal fun showConfirmationBox(message: String, resultCallback: Consumer<Boolean>) {
        val dialog = dialogFactory.confirmationDialog(message, {
            close()
            resultCallback.accept(it)
        })

        show("Confirm", dialog)
    }

    internal fun showInputBox(message: String, filter: Predicate<String>, resultCallback: Consumer<String>) {
        val dialog = dialogFactory.inputDialog(message, filter, Consumer {
            close()
            resultCallback.accept(it)
        })

        show("Input", dialog)
    }

    internal fun showInputBoxWithCancel(message: String, filter: Predicate<String>, resultCallback: Consumer<String>) {
        val dialog = dialogFactory.inputDialogWithCancel(message, filter, Consumer {
            close()
            resultCallback.accept(it)
        })

        show("Input", dialog)
    }

    internal fun showErrorBox(error: Throwable) {
        showErrorBox(error, EmptyRunnable)
    }

    internal fun showErrorBox(error: Throwable, callback: Runnable) {
        val dialog = dialogFactory.errorDialog(error, {
            close()
            callback.run()
        })

        show("Error", dialog)
    }

    internal fun showErrorBox(errorMessage: String, callback: Runnable) {
        val dialog = dialogFactory.errorDialog(errorMessage, {
            close()
            callback.run()
        })

        show("Error", dialog)
    }

    internal fun showBox(message: String, content: Node, vararg buttons: Button) {
        val dialog = dialogFactory.customDialog(message, content, Runnable { close() }, *buttons)

        show("Dialog", dialog)
    }

    internal fun showProgressBox(message: String): UIDialogHandler {
        val dialog = dialogFactory.progressDialogIndeterminate(message, {
            close()
        })

        show("Progress", dialog)

        return object : UIDialogHandler {
            override fun show() {
                // no-op
            }

            override fun dismiss() {
                close()
            }
        }
    }

    internal fun showProgressBox(message: String, observable: DoubleProperty, callback: Runnable) {
        val dialog = dialogFactory.progressDialog(message, observable, {
            close()
            callback.run()
        })

        show("Progress", dialog)
    }

    private class DialogData internal constructor(internal var title: String, internal var contentPane: Pane)
}
{'fraction_non_alphanumeric': 0.10427390422710965, 'fraction_numerical': 0.0033536109811261893, 'mean_word_length': 2.328920041536864, 'pattern_counts': {'":': 0, '<': 21, '<?xml version=': 0, '>': 21, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6437381', 'n_tokens_mistral': 3607, 'n_tokens_neox': 3406, 'n_words': 826}