Skip to content

Commit a99f6d5

Browse files
authored
Merge pull request #2 from scijava/repl-dialog
[FEATURE] Add dialog that has repl tabs as contents * Add dialog that has repl tabs as contents * Add license header
1 parent 0fcbc8c commit a99f6d5

File tree

3 files changed

+203
-10
lines changed

3 files changed

+203
-10
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*-
2+
* #%L
3+
* JavaFX frontend for SciJava JSR-223-compliant scripting plugins.
4+
* %%
5+
* Copyright (C) 2019 HHMI Janelia Research Campus.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
package org.scijava.scripting.fx
30+
31+
import javafx.geometry.Insets
32+
import javafx.scene.control.ButtonType
33+
import javafx.scene.control.Dialog
34+
import javafx.scene.control.DialogPane
35+
import javafx.scene.input.KeyCode
36+
import javafx.scene.input.KeyCodeCombination
37+
import javafx.scene.input.KeyCombination
38+
import javafx.scene.layout.Region
39+
import javafx.stage.Modality
40+
import org.scijava.Context
41+
42+
class SciJavaReplFXDialog @JvmOverloads constructor(
43+
context: Context,
44+
bindings: Map<String, *> = mapOf<String, Any>(),
45+
width: Double? = null,
46+
height: Double? = null,
47+
increaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.EQUALS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
48+
decreaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.MINUS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
49+
evalKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN)),
50+
exitKeyCombination: Collection<KeyCombination> = setOf (KeyCodeCombination(KeyCode.D, KeyCombination.CONTROL_DOWN)),
51+
createNewReplCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)),
52+
cycleTabsForwardCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN)),
53+
cycleTabsBackwardCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN))
54+
) : Dialog<Any>() {
55+
56+
57+
@JvmOverloads constructor(
58+
context: Context,
59+
vararg bindings: Pair<String, *>,
60+
width: Double? = null,
61+
height: Double? = null,
62+
increaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.EQUALS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
63+
decreaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.MINUS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
64+
evalKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN)),
65+
exitKeyCombination: Collection<KeyCombination> = setOf (KeyCodeCombination(KeyCode.D, KeyCombination.CONTROL_DOWN)),
66+
createNewReplCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)),
67+
cycleTabsForwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN)),
68+
cycleTabsBackwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN))
69+
) : this(
70+
context,
71+
mapOf(*bindings),
72+
width,
73+
height,
74+
increaseFontKeys,
75+
decreaseFontKeys,
76+
evalKeys,
77+
exitKeyCombination,
78+
createNewReplCombination,
79+
cycleTabsForwardKombination,
80+
cycleTabsBackwardKombination)
81+
82+
val tabs = ScijavaReplFXTabs(
83+
context = context,
84+
bindings = bindings,
85+
increaseFontKeys = increaseFontKeys,
86+
decreaseFontKeys = decreaseFontKeys,
87+
evalKeys = evalKeys,
88+
exitKeyCombination = exitKeyCombination,
89+
createNewReplCombination = createNewReplCombination,
90+
cycleTabsForwardCombination = cycleTabsForwardCombination,
91+
cycleTabsBackwardCombination = cycleTabsBackwardCombination)
92+
93+
private var widthOnHiding: Double? = width
94+
private var heightOnHiding: Double? = height
95+
private var wasHiding = !isShowing
96+
97+
init {
98+
// need DialogPane with custom createButtonBar to remove empty space at bottom
99+
dialogPane = object: DialogPane() {
100+
override fun createButtonBar() = Region()
101+
}
102+
dialogPane.content = tabs.node
103+
isResizable = true
104+
dialogPane.padding = Insets.EMPTY
105+
initModality(Modality.NONE)
106+
setOnShowing {
107+
if (!tabs.hasPrompts)
108+
tabs.createAndAddTab()
109+
wasHiding = !isShowing
110+
}
111+
setOnShown {
112+
if (wasHiding) {
113+
widthOnHiding?.let { this.width = it }
114+
heightOnHiding?.let { this.height = it }
115+
}
116+
}
117+
setOnHiding {
118+
widthOnHiding = this.width
119+
heightOnHiding = this.height
120+
}
121+
// weirdly, an invisible close button is required for the close icon to work
122+
// https://stackoverflow.com/questions/32048348/javafx-scene-control-dialogr-wont-close-on-pressing-x
123+
// https://stackoverflow.com/questions/37619885/javafx-fxml-dialog-cant-close-it-with-the-x-button?noredirect=1&lq=1
124+
dialogPane.buttonTypes.setAll(ButtonType.CLOSE)
125+
dialogPane
126+
.lookupButton(ButtonType.CLOSE)
127+
.also { it.isVisible = false }
128+
.also { it.managedProperty().bind(it.visibleProperty()) }
129+
130+
}
131+
132+
}

src/main/kotlin/org/scijava/scripting/fx/ScijavaReplFXTabs.kt

+14-10
Original file line numberDiff line numberDiff line change
@@ -40,38 +40,39 @@ import kotlinx.coroutines.GlobalScope
4040
import kotlinx.coroutines.launch
4141
import org.scijava.Context
4242

43-
class ScijavaReplFXTabs(
43+
class ScijavaReplFXTabs @JvmOverloads constructor (
4444
private val context: Context,
45+
private val bindings: Map<String, *> = mapOf<String, Any>(),
4546
private val increaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.EQUALS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
4647
private val decreaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.MINUS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
4748
private val evalKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN)),
4849
private val exitKeyCombination: Collection<KeyCombination> = setOf (KeyCodeCombination(KeyCode.D, KeyCombination.CONTROL_DOWN)),
4950
private val createNewReplCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)),
50-
private val cycleTabsForwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN)),
51-
private val cycleTabsBackwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)),
52-
private val bindings: Map<String, *> = mapOf<String, Any>()
51+
private val cycleTabsForwardCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN)),
52+
private val cycleTabsBackwardCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN))
5353
) {
5454

55+
@JvmOverloads
5556
constructor(
5657
context: Context,
58+
vararg bindings: Pair<String, *>,
5759
increaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.EQUALS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
5860
decreaseFontKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.MINUS, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_ANY)),
5961
evalKeys: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.ENTER, KeyCombination.CONTROL_DOWN)),
6062
exitKeyCombination: Collection<KeyCombination> = setOf (KeyCodeCombination(KeyCode.D, KeyCombination.CONTROL_DOWN)),
6163
createNewReplCombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.T, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)),
6264
cycleTabsForwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN)),
63-
cycleTabsBackwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN)),
64-
vararg bindings: Pair<String, *>
65+
cycleTabsBackwardKombination: Collection<KeyCombination> = setOf(KeyCodeCombination(KeyCode.TAB, KeyCombination.CONTROL_DOWN, KeyCombination.SHIFT_DOWN))
6566
) : this(
6667
context,
68+
mapOf(*bindings),
6769
increaseFontKeys,
6870
decreaseFontKeys,
6971
evalKeys,
7072
exitKeyCombination,
7173
createNewReplCombination,
7274
cycleTabsForwardKombination,
73-
cycleTabsBackwardKombination,
74-
mapOf(*bindings))
75+
cycleTabsBackwardKombination)
7576

7677

7778
private val tabPane = TabPane()
@@ -113,11 +114,11 @@ class ScijavaReplFXTabs(
113114
it.consume()
114115
GlobalScope.launch { repl.evalCurrentPrompt() }
115116
}
116-
cycleTabsForwardKombination.any { c -> c.match(it) } -> {
117+
cycleTabsForwardCombination.any { c -> c.match(it) } -> {
117118
it.consume()
118119
cycleForward()
119120
}
120-
cycleTabsBackwardKombination.any { c -> c.match(it) } -> {
121+
cycleTabsBackwardCombination.any { c -> c.match(it) } -> {
121122
it.consume()
122123
cycleBackward()
123124
}
@@ -135,6 +136,9 @@ class ScijavaReplFXTabs(
135136
}
136137
}
137138

139+
val hasPrompts: Boolean
140+
get() = this.replIds.isNotEmpty()
141+
138142
@Synchronized
139143
private fun addTab(repl: SciJavaReplFX): Int {
140144
val replId = smallestId(replIds.keys)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*-
2+
* #%L
3+
* JavaFX frontend for SciJava JSR-223-compliant scripting plugins.
4+
* %%
5+
* Copyright (C) 2019 HHMI Janelia Research Campus.
6+
* %%
7+
* Redistribution and use in source and binary forms, with or without
8+
* modification, are permitted provided that the following conditions are met:
9+
*
10+
* 1. Redistributions of source code must retain the above copyright notice,
11+
* this list of conditions and the following disclaimer.
12+
* 2. Redistributions in binary form must reproduce the above copyright notice,
13+
* this list of conditions and the following disclaimer in the documentation
14+
* and/or other materials provided with the distribution.
15+
*
16+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
20+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26+
* POSSIBILITY OF SUCH DAMAGE.
27+
* #L%
28+
*/
29+
package org.scijava.scripting.fx
30+
31+
import com.sun.javafx.application.PlatformImpl
32+
import javafx.application.Platform
33+
import javafx.event.EventHandler
34+
import javafx.scene.Scene
35+
import javafx.scene.control.Button
36+
import javafx.scene.control.Dialog
37+
import javafx.stage.Stage
38+
import org.scijava.Context
39+
import kotlin.math.sqrt
40+
41+
fun main() {
42+
43+
val context = Context()
44+
PlatformImpl.startup {}
45+
46+
var dialog: Dialog<Any>? = null
47+
val root = Button("Show _REPL Tab").also { it.onAction = EventHandler { dialog?.show() } }
48+
Platform.runLater {
49+
val scene = Scene(root)
50+
val stage = Stage()
51+
stage.scene = scene
52+
stage.show()
53+
dialog = SciJavaReplFXDialog(context, Pair("mySqrt", { x: Double -> sqrt(x) }), width = 1000.0, height = 750.0)
54+
.also { it.initOwner(root.scene.window) }
55+
}
56+
57+
}

0 commit comments

Comments
 (0)