├── .gitignore
├── settings.gradle
├── examples
├── src
│ ├── test
│ │ └── frege
│ │ │ └── DummyTest.fr
│ └── main
│ │ └── frege
│ │ └── fregefx
│ │ └── example
│ │ ├── HelloWorldAsyncIO.fr
│ │ └── HelloWorld.fr
└── build.gradle
├── fregefx
├── src
│ ├── test
│ │ └── frege
│ │ │ └── DummyTest.fr
│ └── main
│ │ ├── java
│ │ └── org
│ │ │ └── frege
│ │ │ └── JavaFxWorld.java
│ │ ├── frege
│ │ └── fregefx
│ │ │ ├── JavaFxType.fr
│ │ │ └── JavaFxUtils.fr
│ │ └── java8
│ │ └── org
│ │ └── frege
│ │ ├── FregeEventHandler.java
│ │ ├── FregeChangeListener.java
│ │ └── FregeFX.java
├── build.gradle
└── types.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── .idea
├── vcs.xml
├── libraries
│ └── Gradle__org_frege_lang_frege_3_24_400.xml
├── gradle.xml
└── modules.xml
├── allJavaFX.groovy
├── fregefx.iml
├── LICENSE.txt
├── gradlew.bat
├── README.md
└── gradlew
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build
3 | target
4 | out
5 | *_
6 | generated
7 | .settings
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'fregefx'
2 |
3 | include 'fregefx'
4 | include 'examples'
--------------------------------------------------------------------------------
/examples/src/test/frege/DummyTest.fr:
--------------------------------------------------------------------------------
1 | module DummyTest where
2 |
3 | import Test.QuickCheck
4 |
5 | dummy = once true
--------------------------------------------------------------------------------
/fregefx/src/test/frege/DummyTest.fr:
--------------------------------------------------------------------------------
1 | module DummyTest where
2 |
3 | import Test.QuickCheck
4 |
5 | dummy = once true
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Frege/FregeFX/master/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | group = org.frege-lang
2 | version = 0.8.2-SNAPSHOT
3 |
4 |
5 | fregeRelease = 3.24public
6 | fregeVersion = 3.24.400
7 |
8 | javaTarget = 1.8
9 |
--------------------------------------------------------------------------------
/fregefx/src/main/java/org/frege/JavaFxWorld.java:
--------------------------------------------------------------------------------
1 | package org.frege;
2 |
3 | public interface JavaFxWorld {
4 | public static final JavaFxWorld INSTANCE = new JavaFxWorld() {};
5 | }
6 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sat Apr 14 14:03:34 CEST 2018
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
7 |
--------------------------------------------------------------------------------
/.idea/libraries/Gradle__org_frege_lang_frege_3_24_400.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/allJavaFX.groovy:
--------------------------------------------------------------------------------
1 | def base = '/Users/dierkkoenig/Downloads/javafx-src/'
2 | File sources = new File(base)
3 |
4 | sources.eachFileRecurse { File file ->
5 | def name = file.path - base
6 | if (! name.endsWith(".java")) return
7 | if (! name.contains("javafx")) return
8 | if (name.contains("com/sun")) return
9 |
10 | name -= ".java"
11 |
12 | def className = name.replaceAll(/\//, '.' )
13 |
14 | println "processing $name"
15 |
16 | "gradlew -DnativeClassName=$className -DoutputFile=build/generated/frege/${name}.fr :preFregeFX:fNG".execute()
17 |
18 | sleep 3000
19 | }
--------------------------------------------------------------------------------
/fregefx/src/main/frege/fregefx/JavaFxType.fr:
--------------------------------------------------------------------------------
1 | module fregefx.JavaFxType where
2 |
3 | --- Analogon to Realworld
4 | data JFXWorld = pure native org.frege.JavaFxWorld
5 |
6 | --- Analogon to IO
7 | type JFX = ST JFXWorld
8 |
9 | -- in STM is it like so
10 | --data JFX a = JFX (ST JFXWorld a)
11 | --atomically :: JFX α -> IO α
12 | --atomically (State s a) = return a
13 |
14 | --- Analogon to MutableIO
15 | type MutableJFX = Mutable JFXWorld
16 |
17 | --- Analogon to IOMutable
18 | type JFXMutable d = JFX (MutableJFX d)
19 |
20 | --- A mutable reference to a value in the JFX context
21 | type JFXRef a = MutableJFX (Ref a)
22 |
--------------------------------------------------------------------------------
/fregefx.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
--------------------------------------------------------------------------------
/fregefx/src/main/java8/org/frege/FregeEventHandler.java:
--------------------------------------------------------------------------------
1 | package org.frege;
2 |
3 | import frege.prelude.PreludeBase;
4 | import frege.run8.Func;
5 | import frege.run8.Lazy;
6 | import frege.run8.Thunk;
7 | import frege.runtime.Phantom.RealWorld;
8 | import javafx.event.Event;
9 | import javafx.event.EventHandler;
10 |
11 | // type t -> IO () ==> Func.U>
12 |
13 | public class FregeEventHandler implements EventHandler {
14 | protected Func.U> lambda;
15 |
16 | public FregeEventHandler(Func.U> lambda) {
17 | this.lambda = lambda;
18 | }
19 |
20 | @Override
21 | public void handle(T event) {
22 | Lazy lazyEvent = Thunk.lazy(event);
23 | try {
24 | PreludeBase.TST.performUnsafe( lambda.apply(lazyEvent).call() ).call();
25 | } catch(RuntimeException re) {
26 | re.printStackTrace();
27 | throw re;
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/examples/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | // use if java sources have to be compiled
3 | //project.tasks.compileFrege.dependsOn(project.tasks.compileJava) // make java compile first
4 | //sourceSets {
5 | // main {
6 | // java {
7 | // compileClasspath += project.files("build/classes/main")
8 | // }
9 | // }
10 | //}
11 |
12 |
13 | apply plugin: 'application'
14 |
15 | mainClassName = "fregefx.example.HelloWorld"
16 |
17 | dependencies {
18 | compile project(':fregefx')
19 | }
20 |
21 | def javaVersion = System.getProperty('java.version') ?: "unknown-version"
22 | def jdk8 = javaVersion.startsWith("1.8")
23 | def jdk9 = javaVersion.startsWith("9.")
24 |
25 | if (! (jdk8 || jdk9)) {
26 | println "You should be using Java 8 or 9 (with JavaFX module) but you run $javaVersion ."
27 | }
28 |
29 |
30 | fregeQuickCheck {
31 | // help = true // default: false
32 | // listAvailable = true // default: false
33 | // verbose = false // default: true
34 | // num = 500 // default: 100
35 | // includePredicates = ['myFirstPred', 'mySecondPred']
36 | // excludePredicates = ['myFirstPred', 'mySecondPred']
37 | // moduleName = 'DummyTest' // prio 1
38 | // moduleJar = 'path/to/my/module.jar' // prio 2
39 | // moduleDir = "$project.buildDir/classes/test" // prio 3, default
40 | // classpathDirectories = ["$project.buildDir/classes/main", "$project.buildDir/classes/test"]
41 | // allJvmArgs = ['-Xss4M']
42 | }
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/fregefx/src/main/java8/org/frege/FregeChangeListener.java:
--------------------------------------------------------------------------------
1 | package org.frege;
2 |
3 | import javafx.beans.value.ChangeListener;
4 | import javafx.beans.value.ObservableValue;
5 | import frege.runtime.Phantom.RealWorld;
6 | import frege.prelude.PreludeBase;
7 | import frege.run8.Func;
8 | import frege.run8.Lazy;
9 | import frege.run8.Thunk;
10 |
11 | //type t -> IO () ==> Func.U>>
12 |
13 | public class FregeChangeListener implements ChangeListener {
14 | protected Func.U>> lambda;
15 |
16 | public FregeChangeListener(Func.U>> lambda) {
17 | this.lambda = lambda;
18 | }
19 |
20 | /**
21 | * @param observable It is by design that we do not make use of the of this object. It would introduce more coupling.
22 | */
23 | @Override
24 | public void changed(ObservableValue extends T> observable, T oldValue, T newValue) {
25 | try {
26 | Lazy alt = Thunk.lazy(oldValue);
27 | Lazy neu = Thunk.lazy(newValue);
28 | PreludeBase.TST.performUnsafe(lambda.apply(alt).call().apply(neu).call()).call();
29 | // Applicable inter = lambda.apply(oldValue).apply(newValue);
30 | // Delayed.forced(inter.apply(null).result().forced()); // the second argument is the IO context
31 | } catch(RuntimeException re) {
32 | re.printStackTrace();
33 | throw re;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/examples/src/main/frege/fregefx/example/HelloWorldAsyncIO.fr:
--------------------------------------------------------------------------------
1 | {--
2 | Like HelloWorld but running all IO actions outside the UI Application thread
3 | asynchronously but in strict order. Pretty much an actor.
4 | -}
5 | module fregefx.example.HelloWorldAsyncIO where
6 |
7 | import frege.Prelude hiding(ListView)
8 | import fregefx.JavaFxType
9 | import fregefx.JavaFxAll
10 | import fregefx.JavaFxUtils
11 |
12 | import Control.Concurrent
13 |
14 | type IOQueue = MVar (IO ())
15 |
16 | main args = do
17 | ioQ <- MVar.newEmpty
18 | FregeFX.launch $ withStage (buildUI ioQ) -- runs in UI Thread
19 | loop ioQ -- runs in main Thread
20 |
21 | loop :: IOQueue -> IO()
22 | loop ioQ = do
23 | ioAction <- ioQ.take
24 | result <- ioAction
25 | loop ioQ
26 |
27 | runIn :: IOQueue -> IO() -> IO ()
28 | runIn ioQ ioAction =
29 | ioQ.put ioAction >> return ()
30 |
31 |
32 | buildUI :: Family a => IOQueue -> a -> Stage -> JFX a
33 | buildUI ioQ root stage = do
34 | stage.setTitle "FregeFX Hello World"
35 | root <: do
36 | vbox <- VBox.new 5d :: JFX VBox
37 | vbox.setPadding =<< insets 10
38 | vbox <: do
39 | button <- Button.new "Please click me for JFX action"
40 | button `action_` (button.setText "Thanks!") -- IO forbidden by type
41 | vbox <: do
42 | button <- Button.new "Print async to console."
43 | button `actionIO_` (runIn ioQ (println "Printing asynchronously outside") ) -- JFX change forbidden by type
44 |
45 |
46 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | Copyright © 2011-2015, Ingo Wechsung
4 | All rights reserved.
5 |
6 | Redistribution and use in source and binary forms, with or
7 | without modification, are permitted provided that the following
8 | conditions are met:
9 |
10 | Redistributions of source code must retain the above copyright
11 | notice, this list of conditions and the following disclaimer.
12 |
13 | Redistributions in binary form must reproduce the above
14 | copyright notice, this list of conditions and the following
15 | disclaimer in the documentation and/or other materials provided
16 | with the distribution.
17 |
18 | Neither the name of the copyright holder nor the names of its
19 | contributors may be used to endorse or promote products derived
20 | from this software without specific prior written permission.
21 |
22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 | FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 | COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
32 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
33 | THE POSSIBILITY OF SUCH DAMAGE.
34 |
35 |
36 |
--------------------------------------------------------------------------------
/fregefx/src/main/java8/org/frege/FregeFX.java:
--------------------------------------------------------------------------------
1 | package org.frege;
2 |
3 | import frege.runtime.*;
4 | import frege.runtime.Phantom.RealWorld;
5 | import frege.prelude.PreludeBase;
6 | import frege.run8.Func;
7 | import frege.run8.Lazy;
8 | import frege.run8.Thunk;
9 | import javafx.application.Application;
10 | import javafx.fxml.FXMLLoader;
11 | import javafx.scene.Parent;
12 | import javafx.scene.control.Label;
13 | import javafx.stage.Stage;
14 |
15 | // The type of Stage -> IO () is
16 | // Func.U>
17 |
18 | import java.io.IOException;
19 |
20 | public class FregeFX extends Application {
21 | private static Func.U> lambda;
22 |
23 | @Override
24 | public void start(Stage primaryStage) throws Exception {
25 | final Lazy lazyStage= Thunk.lazy(primaryStage);
26 | try {
27 | PreludeBase.TST.performUnsafe(lambda.apply(lazyStage).call()).call();
28 | } catch(RuntimeException re) {
29 | re.printStackTrace();
30 | throw re;
31 | }
32 | }
33 |
34 | /**
35 | * @param callback The callback lambda that will receive the primaryStage to work on.
36 | */
37 | public static void launch(Func.U> callback) {
38 | lambda = callback;
39 | Application.launch();
40 | }
41 |
42 | public static Parent fxml(String className, String resourceName ) {
43 | try {
44 | return FXMLLoader.load(Class.forName(className).getClass().getResource(resourceName));
45 | } catch (ClassNotFoundException e) {
46 | e.printStackTrace();
47 | } catch (IOException e) {
48 | e.printStackTrace();
49 | } catch (NullPointerException e) {
50 | e.printStackTrace();
51 | }
52 | return new Label("could not load " + resourceName);
53 | }
54 |
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/examples/src/main/frege/fregefx/example/HelloWorld.fr:
--------------------------------------------------------------------------------
1 | {--
2 | A simple example of a JavaFX UI with Frege:
3 | a group with a vbox of two buttons plus simple onAction handlers.
4 | UI construction follows a _builder_ style approach,
5 | i.e. the implementation details of how to add sub nodes to a parent is hidden
6 | but the containment structure is visible in the code layout.
7 | -}
8 | module fregefx.example.HelloWorld where
9 |
10 | import frege.Prelude hiding(ListView)
11 | import fregefx.JavaFxType
12 | import fregefx.JavaFxAll
13 | import fregefx.JavaFxUtils
14 |
15 | import Control.Concurrent
16 |
17 | main args = do
18 | FregeFX.launch $ withStage buildUI -- runs in UI Thread
19 |
20 | buildUI :: Family a => a -> Stage -> JFX a
21 | buildUI root stage = do
22 | stage.setTitle "FregeFX Hello World"
23 | root <: do
24 | vbox <- VBox.new 5d :: JFX VBox
25 | vbox.setPadding =<< insets 10
26 | vbox <: do
27 | button <- Button.new "Please click me for JFX action"
28 | button `action_` (button.setText "Thanks!") -- IO forbidden by type
29 | vbox <: do
30 | button <- Button.new "Print current thread to console"
31 | button `actionIO_` do -- JFX change forbidden by type
32 | thread <- Thread.current()
33 | name <- thread.getName
34 | println $ "thread is " ++ name
35 | vbox <: do
36 | button <- Button.new "Bridge from async IO to JFX inside UI thread"
37 | bridgeAction button (Thread.current() >>= _.getName) button.setText
38 | vbox <: do
39 | button <- Button.new "Async action can only be IO"
40 | button `actionIO_` do
41 | async do -- this is async inside async, but who cares
42 | println "printed outside UI thread"
43 | inIO button.getText println
44 | return ()
45 | vbox <: do
46 | button <- Button.new "Async plus wait for completion"
47 | button `actionIO_` do
48 | mResult <- MVar.newEmpty -- for thread coordination
49 | async do
50 | println "printed outside UI thread"
51 | mResult.put "done"
52 | mResult.take
53 | println "waited for completion, proceed in UI thread"
54 | -- experiment that dynamically adds 5 buttons
55 | vbox `addAll` map (Button.new . ("Button "++) . show) [1..5]
56 |
57 |
58 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FregeFX
2 | Frege language binding and utilities to create JavaFX user interfaces
3 |
4 | [  ](https://bintray.com/fregelang/FregeFX/fregefx/_latestVersion)
5 |
6 | ## Prerequisites
7 |
8 | Java8_u40 or higher (which includes JavaFX 8, which we need here)
9 |
10 | ## Usage
11 |
12 | Run the example via
13 |
14 | gradlew run
15 |
16 | ## Introduction:
17 |
18 | [Talk from JavaOne 2016](https://www.youtube.com/watch?v=CZr8RLJsZqc)
19 |
20 | ## Known uses:
21 |
22 | * [The FregeFX repl](https://github.com/Dierk/frepl-gui)
23 | * The [animated image viewer](https://github.com/Dierk/fregeTutorial/blob/master/src/main/frege/CoverFlow.fr)
24 | in the [Frege Tutorial](https://github.com/Dierk/fregeTutorial/),
25 | [video](https://www.youtube.com/watch?v=pxKJ_KPLml8)
26 | * Purely Functional Doodle [video](https://www.youtube.com/watch?v=9V7w-RSC_1A)
27 | * Ant Colony STM Demo [video](https://www.youtube.com/watch?v=mu6urVc2Z8Q)
28 |
29 | ## Build & Install
30 |
31 | For local build and install use
32 |
33 | gradlew install
34 |
35 | For running the contained `example` project use
36 |
37 | gradlew run
38 |
39 | ## Release Notes
40 |
41 | ### Release 0.8
42 |
43 | Full Java 8 compatibility for both, compiling and running.
44 |
45 | Makes use of the Frege 3.24 release, version 3.24.400, with full support for generics.
46 |
47 | ### Release 0.3.3 0.3.4
48 |
49 | Releases to test-drive and finally execute the upload to bintray and jcenter.
50 |
51 | ### Release 0.3.1
52 |
53 | The first release to support the 3.24-7.x Frege compiler.
54 |
55 | The API has been to a large extent commented out as it will change with upcoming changes to the
56 | Frege compiler and native declarations where things will get dramatically simpler.
57 | Anyway, enough is left to support the
58 | [Frege Tutorial](https://github.com/Dierk/fregeTutorial)
59 |
60 | All compilation targets Java 7 (even though you need to compile and run with Java 8).
61 | The user of this library also needs to compile with the same setting, i.e.:
62 |
63 | * use Java 8 for compiling and running
64 | * set target=1.7 for both, the Java and Frege compiler
65 | * use the 3.24-7.30 Frege compiler.
66 |
67 | # Copyright and License
68 |
69 | Copyright (c) Dierk König, 2016. All rights reserved.
70 | The use and distribution terms for this software are covered by the
71 | [BSD 3-clause license](http://opensource.org/licenses/BSD-3-Clause)
72 | which can be found in the file LICENSE.txt at the root of this distribution.
73 | By using this software in any fashion, you are agreeing to be bound by the terms of this license.
74 | You must not remove this notice, or any other, from this software.
75 |
--------------------------------------------------------------------------------
/fregefx/build.gradle:
--------------------------------------------------------------------------------
1 | plugins {
2 | id "com.jfrog.bintray" version "1.7.3"
3 | }
4 |
5 | apply plugin: 'maven'
6 | apply plugin: 'maven-publish'
7 |
8 | task sourcesJar(type: Jar, dependsOn: classes) {
9 | classifier = 'sources'
10 | from sourceSets.main.allSource
11 | }
12 |
13 | task javadocJar(type: Jar, dependsOn: javadoc) {
14 | classifier = 'javadoc'
15 | from javadoc.destinationDir
16 | }
17 |
18 | artifacts {
19 | archives sourcesJar
20 | archives javadocJar
21 | }
22 |
23 | publishing {
24 | publications {
25 | FregeFxPublication(MavenPublication) {
26 | from components.java
27 | artifact sourcesJar
28 | artifact javadocJar
29 | groupId group
30 | artifactId 'fregefx'
31 | version project.version
32 | }
33 | }
34 | }
35 |
36 | bintray { // see https://github.com/bintray/gradle-bintray-plugin
37 | user = project.hasProperty('bintrayUser') ? bintrayUser : "" // from /gradle.properties
38 | key = project.hasProperty('bintrayKey') ? bintrayKey : "" // from /gradle.properties
39 | publications = ['FregeFxPublication']
40 | pkg {
41 | repo = 'FregeFX'
42 | name = 'fregefx'
43 | desc = 'FregeFX - JavaFX with Frege (Haskell for the JVM)'
44 | userOrg = "fregelang"
45 | licenses = ['BSD 3-Clause']
46 | vcsUrl = 'https://github.com/Frege/FregeFX.git'
47 | websiteUrl = 'https://github.com/Frege/FregeFX'
48 | issueTrackerUrl = 'https://github.com/Frege/FregeFX/issues'
49 | githubRepo = 'Frege/FregeFX'
50 | githubReleaseNotesFile = 'README.md'
51 | publicDownloadNumbers = true
52 | version {
53 | name = project.version
54 | desc = 'FregeFX - Frege language binding for JavaFX'
55 | //released = new Date() // optional; does not work atm
56 | vcsTag = project.version
57 | attributes = [:]
58 | // Optional configuration for Maven Central sync of the version
59 | // we currently don't upload to mavenCentral as it is too cumbersome and
60 | // jcenter is good enough to care for all artifacts.
61 | // This way, we also get better download stats.
62 | // mavenCentralSync {
63 | // sync = false == project.version.toString().endsWith("-SNAPSHOT") //Optional (true by default). Determines whether to sync the version to Maven Central.
64 | // user = project.hasProperty('sonatypeUsername') ? sonatypeUsername : "" //OSS user token
65 | // password = project.hasProperty('sonatypePassword') ? sonatypePassword : "" //OSS user password
66 | // close = '1' //Optional property. By default the staging repository is closed and artifacts are released to Maven Central. You can optionally turn this behaviour off (by puting 0 as value) and release the version manually.
67 | // }
68 | }
69 | }
70 | }
71 |
72 |
73 | project.tasks.compileFrege.dependsOn(project.tasks.compileJava)
74 |
75 | ext {
76 | jfxLibDir = locateJfxLibDir()
77 | }
78 |
79 | dependencies {
80 | if (jfxLibDir) {
81 | runtime files("$jfxLibDir/jfxrt.jar")
82 | } // TODO: find out why this seems to be necessary even on JDK 8
83 | }
84 |
85 | boolean runningOnJDK8() {
86 | System.getProperty('java.version')[0..2].toDouble() == 1.8
87 | }
88 |
89 |
90 | fregeDoc {
91 | // xss = "8m"
92 | }
93 |
94 | String locateJfxLibDir() {
95 | def javaFxHome = System.env['JAVAFX_HOME'] ?: ''
96 | def javaHome = System.env['JAVA_HOME'] ?: ''
97 | def jdk8 = System.getProperty('java.version').startsWith('1.8')
98 | def jdk9 = System.getProperty('java.version').startsWith('9.')
99 |
100 | if (jdk9) {
101 | try {
102 | Class.forName('javafx.application.Platform', false, this.getClass().getClassLoader())
103 | } catch (e) {
104 | def message = "Your Java 9 version does not include JavaFX, validate via 'java --list-modules'."
105 | throw new GradleScriptException(message, e)
106 | }
107 | return null
108 | }
109 |
110 | // we should run with Java 8.
111 | if (!jdk8) {
112 | throw new GradleScriptException("Please use Java 8.", null)
113 | }
114 |
115 | def jdkHome = System.properties.'java.home' ?: ''
116 |
117 | def result = "$javaFxHome/rt/lib"
118 | if (new File("$result/jfxrt.jar").exists()) {
119 | println "using javafx from explicit JAVAFX_HOME: $result"
120 | return result
121 | }
122 | result = "$jdkHome/lib/ext/"
123 | if (jdk8 && new File("$result/jfxrt.jar").exists()) {
124 | println "using javafx from current java 8: $result"
125 | return result
126 | }
127 | result = "$javaHome/jre/lib/"
128 | if (new File("$result/jfxrt.jar").exists()) {
129 | println "using javafx from explicit JAVA_HOME: $result"
130 | return result
131 | }
132 | result = "$javaHome/lib/"
133 | if (new File("$result/jfxrt.jar").exists()) {
134 | println "using javafx from explicit JAVA_HOME: $result"
135 | return result
136 | }
137 | logger.error "please use a Java Version 8"
138 | logger.error " or set JAVA_HOME to a dir that contains the jre/lib/jfxrt.jar"
139 | logger.error " or set JAVAFX_HOME to a dir that contains the rt/lib/jfxrt.jar"
140 | throw new GradleScriptException("location of jfxrt.jar could not be determined", null)
141 | }
142 | //
143 | //fregeNativeGen {
144 | //// typesFile = "$projectDir/src/main/resources/types.properties"
145 | // className = System.properties.nativeClassName //"javafx.scene.control.Button"
146 | // outputFile = file(System.properties.outputFile) // outputFile
147 | //}
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/fregefx/src/main/frege/fregefx/JavaFxUtils.fr:
--------------------------------------------------------------------------------
1 | module fregefx.JavaFxUtils where
2 |
3 | import frege.Prelude hiding(ListView)
4 |
5 | import fregefx.JavaFxType
6 | import fregefx.JavaFxAll
7 |
8 | {- define the Java stuff inline ... this way it works for both java7/java8 -}
9 | native module where {
10 | public static class FregeFX extends javafx.application.Application {
11 | private static Func.U> lambda;
12 |
13 | @Override
14 | public void start(javafx.stage.Stage primaryStage) throws Exception {
15 | final Lazy lazyStage= Thunk.lazy(primaryStage);
16 | try {
17 | lambda.apply(lazyStage).call().apply(Thunk.lazy(org.frege.JavaFxWorld.INSTANCE)).call();
18 | } catch(RuntimeException re) {
19 | re.printStackTrace();
20 | throw re;
21 | }
22 | }
23 |
24 | /**
25 | * @param callback The callback lambda that will receive the primaryStage to work on.
26 | */
27 | public static void launch(Func.U> callback) {
28 | lambda = callback;
29 | javafx.application.Application.launch();
30 | }
31 |
32 | public static javafx.scene.Parent fxml(String className, String resourceName ) {
33 | try {
34 | return javafx.fxml.FXMLLoader.load(Class.forName(className).getClass().getResource(resourceName));
35 | } catch (ClassNotFoundException e) {
36 | e.printStackTrace();
37 | } catch (java.io.IOException e) {
38 | e.printStackTrace();
39 | } catch (NullPointerException e) {
40 | e.printStackTrace();
41 | }
42 | return new javafx.scene.control.Label("could not load " + resourceName);
43 | }
44 | }
45 |
46 | // event handling
47 | public static javafx.event.EventHandler
48 | onAction(final Func.U> lambda) {
49 | return new javafx.event.EventHandler() {
50 | @Override
51 | public void handle(T event) {
52 | Lazy lazyEvent = Thunk.lazy(event);
53 | try {
54 | lambda.apply(lazyEvent).call().apply(Thunk.lazy(org.frege.JavaFxWorld.INSTANCE)).call();
55 | } catch(RuntimeException re) {
56 | re.printStackTrace();
57 | throw re;
58 | }
59 | }
60 | };
61 | }
62 |
63 | // change handling
64 | public static javafx.beans.value.ChangeListener
65 | onChange(final Func.U>> lambda) {
66 | return new javafx.beans.value.ChangeListener() {
67 | @Override
68 | public void changed(javafx.beans.value.ObservableValue extends T> observable, T oldValue, T newValue) {
69 | try {
70 | Lazy alt = Thunk.lazy(oldValue);
71 | Lazy neu = Thunk.lazy(newValue);
72 | lambda.apply(alt).call().apply(neu).call().apply(Thunk.lazy(org.frege.JavaFxWorld.INSTANCE)).call();
73 | } catch(RuntimeException re) {
74 | re.printStackTrace();
75 | throw re;
76 | }
77 | }
78 | };
79 | }
80 |
81 | // bridging async IO actions to JFX actions, relaying any value that was obtained in IO as pure for rendering in JFX
82 | public static void doBridge(final Func.U ioLambda, final Func.U> jfxLambda) {
83 | try {
84 | final java.util.concurrent.FutureTask