Introducing fontawesomefx-examples project

Some people asked me about a FontAwesomeFX tutorial.
Now I started a new project: fontawesomefx-examples at GitHub!

basic_1

The examples will always reflect the latest version of FontAwesomeFX (currently 8.12 which can be loaded from Bintray) and I am going to extend it soon to show all stuff which provided by the lib.

FontAweseomFX 8.12 release informations

ShichimiFX 1.0.5 released

I have released ShichimiFX 1.0.5.

Get more info and the code from my ShichimiFX Bitbucket Repo

Maven

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>shichimifx</artifactId>
  <version>1.0.5</version>
</dependency>

UI for Refuel

This release contains a Frontend for Refuel an application update API written by Dino Tsoumakis which is used with MQTT.fx 0.0.13.

updates-available

updates-load

ShichimiFX 1.0.4 released

I have released ShichimiFX 1.0.4.

Get the code from my ShichimiFX Bitbucket Repo

Maven

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>shichimifx</artifactId>
  <version>1.0.4</version>
</dependency>

This release contains 2 new utility classes I needed for MQTT.fx‘s script editing function Desktop and Shell.

By now I used to open a script for editing with the system default editor via java.awt.Desktop. So far this works well on my Mac but there were issues on Windows and Linux. To get rid of these issues I create my own Desktop class to open the script directly with the system shell:

Desktop

public class Desktop {

    public static boolean edit(String fileToEdit) {
        return openWithSystem(fileToEdit);
    }

    private static boolean openWithSystem(String fileToOpen) {
        if (OS.isLinux()) {
            if (Shell.canOpen("gnome-open", fileToOpen)) {
                return true;
            } else if (Shell.canOpen("kde-open", fileToOpen)) {
                return true;
            } else if (Shell.canOpen("xdg-open", fileToOpen)) {
                return true;
            }
        } else if (OS.isWindows()) {
            if (Shell.canOpen("explorer", fileToOpen)) {
                return true;
            }
        } else if (OS.isMac()) {
            if (Shell.canOpen("open", fileToOpen)) {
                return true;
            }
        }
        return false;
    }
}

Shell

public class Shell {

    public static boolean canOpen(String... command) {
        try {
            ProcessBuilder builder = new ProcessBuilder(command);
            Process process = builder.directory(new File(System.getProperty("user.home"))).start();
            if (process == null) {
                return false;
            }
            try {
                process.exitValue();
                // if this does not throw an IllegalThreadStateException the process is not running/has exited immediately
                return false;
            } catch (IllegalThreadStateException e) {
                // the process seems to be in a running state
                return true;
            }
        } catch (IOException ex) {
            return false;
        }
    }

    public static List<String> prepareOpenFileLine(String command, String fileToOpen) {
        List<String> commandList = new ArrayList<>();
        for (String s : command.split(" ")) {
            commandList.add(s.trim());
        }
        commandList.add(fileToOpen);
        return commandList;
    }

    public static Optional<Process> execute(List<String> command) throws IOException {
        return execute(new File(System.getProperty("user.home")), command);
    }

    public static Optional<Process> execute(File directory, String... command) throws IOException {
        return execute(directory, Arrays.asList(command));
    }

    public static Optional<Process> execute(String... command) throws IOException {
        return Shell.execute(new File(System.getProperty("user.home")), command);
    }

    public static Optional<Process> execute(File directory, List<String> command) throws IOException {
        ProcessBuilder builder = new ProcessBuilder(command);
        Process process = builder.directory(directory).start();
        return Optional.of(process);
    }
}

ShichimiFX 1.0.3 released

I have released ShichimiFX 1.0.3.

Get the code from my ShichimiFX Bitbucket Repo

Maven

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>shichimifx</artifactId>
  <version>1.0.3</version>
</dependency>

This release mostly focuses on the ConsoleStream. I have fixed some performance issues. Also optionally now an alternate stream can be given, e.g. to pass through System.out.
This is used for displaying the logging stream in my lastest release of MQTT.fx.

mqttfx-log-tab

public class ConsoleDude {

    public final static PrintStream STD_OUT = System.out;
    public final static PrintStream STD_ERR = System.err;
    private static BooleanProperty stdStreamsHooked = new SimpleBooleanProperty();

    public static void hookStdStreams(TextInputControl outputArea) {
        PrintStream psOut = new PrintStream(new ConsoleStream(outputArea, System.out), true);
        System.setOut(psOut);
        PrintStream psErr = new PrintStream(new ConsoleStream(outputArea, System.err), true);
        System.setOut(psErr);
        stdStreamsHookedProperty().set(true);
    }

    public static void restoreStdStreams() {
        System.setOut(STD_OUT);
        System.setErr(STD_ERR);
        stdStreamsHookedProperty().set(false);
    }

    public static BooleanProperty stdStreamsHookedProperty() {
        if (stdStreamsHooked == null) {
            stdStreamsHooked = new SimpleBooleanProperty();
        }
        return stdStreamsHooked;
    }

    public boolean isHooked() {
        return stdStreamsHookedProperty().get();
    }

    public static ConsoleStreamHandler createConsoleStreamHandler(TextInputControl outputArea) {
        return createConsoleStreamHandler(outputArea, new SimpleFormatter());
    }

    public static ConsoleStreamHandler createConsoleStreamHandler(TextInputControl outputArea, Formatter formatter) {
        return new ConsoleStreamHandler(new ConsoleStream(outputArea), formatter);
    }

}
public class ConsoleStream extends ByteArrayOutputStream {

    private final TextInputControl textOutputComponent;
    private final StringBuilder buffer;
    private final String EOL = System.getProperty("line.separator");
    private final PrintStream printStream;

    public ConsoleStream(TextInputControl ta) {
        this(ta, null);
    }

    public ConsoleStream(TextInputControl ta, PrintStream printStream) {
        this.textOutputComponent = ta;
        this.printStream = printStream;
        buffer = new StringBuilder(80);
    }

    @Override
    public void flush() throws IOException {
        String text = toString();
        if (text.length() == 0) {
            return;
        }
        append(text);
        reset();
    }

    private void append(String text) {
        if (textOutputComponent.getLength() == 0) {
            buffer.setLength(0);
        }
        if (EOL.equals(text)) {
            buffer.append(text);
        } else {
            buffer.append(text);
            clearBuffer();
        }
    }

    private void clearBuffer() {
        String line = buffer.toString();
        Platform.runLater(() -> {
            textOutputComponent.appendText(line);
        });
        if (printStream != null) {
            printStream.print(line);
        }
        buffer.setLength(0);
    }

}

ShichimiFX 1.0.1 released

I have added extracted some more classes from my application projects (e.g. from MQTT.fx) and added them as new features to ShichimiFX (and released 1.0.1).

Get the code from my ShichimiFX Bitbucket Repo

Maven

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>shichimifx</artifactId>
  <version>1.0.1</version>
</dependency>

AnimationDude
Provides support for Fade-in/Fade-out-Transition of controls:
AnimationDude.addInOutFadeTransition(Duration duration, Node node)
AnimationDude.addInOutFadeTransition(Duration duration, Node nodeToFade, Node trigger)

Make a ListCell (this) a trigger to to fade in a button bar on mouse hover:
AnimationDude.addInOutFadeTransition(Duration.millis(200), buttonsBox, this);

public class AnimationDude {
    
    public final static void  addInOutFadeTransition(Duration duration, Node node) {
        addInOutFadeTransition(duration, node, node);
    }

    public final static void  addInOutFadeTransition(Duration duration, Node nodeToFade, Node trigger) {
        nodeToFade.setOpacity(0.0);
        final FadeTransition fadeOutTransition = new FadeTransition(duration, nodeToFade);
        fadeOutTransition.setFromValue(1.0);
        fadeOutTransition.setToValue(0.0);
        final FadeTransition fadeInTransition = new FadeTransition(duration, nodeToFade);
        fadeInTransition.setFromValue(0.0);
        fadeInTransition.setToValue(1.0);
        trigger.setOnMouseEntered(e->{
                    fadeOutTransition.stop();
                    fadeInTransition.play();
        });
        trigger.setOnMouseExited(e->{
                    fadeInTransition.stop();
                    fadeOutTransition.play();
        });
    }
}

ConsoleDude
Provides support for switching System.out/Sytem.err (ConsoleStream)or bypassing a logging output (ConsoleStreamHandler) a JavaFX text components.

Usage

Use “stdOutMessageArea” for System.out and System.err output:
hook StdOut + StdErr: ConsoleDude.hookStdOutTo(stdOutMessageArea);
restore StdOut + StdErr: ConsoleDude.restoreStdOut();

Also you can observe the status, e. g.:
hookButton.disableProperty().bind(ConsoleDude.stdOutHookedProperty());
releaseButton.disableProperty().bind(ConsoleDude.stdOutHookedProperty().not());

Use “logMessageArea” for logging output:
LOGGER.addHandler(ConsoleDude.createConsoleStreamHandler(logMessageArea));

public class ConsoleStream extends OutputStream {

    private final TextInputControl output;

    public ConsoleStream(TextInputControl ta) {
        this.output = ta;
    }

    @Override
    public void write(int i) throws IOException {
        Platform.runLater(() -> {
            output.appendText(String.valueOf((char) i));
        });
    }
}
public class ConsoleStreamHandler extends StreamHandler{

    public ConsoleStreamHandler(OutputStream out, Formatter formatter) {
        super(out, formatter);
    }

    @Override
    public synchronized void publish(LogRecord record) {
        super.publish(record);
        flush();
    }
}
public class ConsoleDude {

    public final static PrintStream STD_OUT = System.out;
    public final static PrintStream STD_ERR = System.err;
    private static BooleanProperty stdOutHooked = new SimpleBooleanProperty();

    public static void hookStdOutTo(TextInputControl outputArea) {
        PrintStream ps = new PrintStream(new ConsoleStream(outputArea), true);
        System.setOut(ps);
        System.setErr(ps);
        stdOutHookedProperty().set(true);
    }

    public static void restoreStdOut() {
        System.setOut(STD_OUT);
        System.setErr(STD_ERR);
        stdOutHookedProperty().set(false);
    }

    public static BooleanProperty stdOutHookedProperty() {
        if (stdOutHooked == null) {
            stdOutHooked = new SimpleBooleanProperty();
        }
        return stdOutHooked;
    }

    public boolean isHooked() {
        return stdOutHookedProperty().get();
    }

    public static ConsoleStreamHandler createConsoleStreamHandler(TextInputControl outputArea) {
        return createConsoleStreamHandler(outputArea,new SimpleFormatter());
    }

    public static ConsoleStreamHandler createConsoleStreamHandler(TextInputControl outputArea, Formatter formatter) {
        return new ConsoleStreamHandler(new ConsoleStream(outputArea), formatter);
    }

}

FontAwesomeFX 8.0.9 with 40 new icons

I have updated FontAwesomeFX and released version 8.0.9.
A few days ago the FontAwesome 4.2.0 was released with 40 additional icons (FontAwesome now contains 479 icons).

Also I added a simple browser to preview all contained icons.
You can start it via: de.jensd.fx.fontawesome.test.IconOverview

iconsbrowser_8.0.9

Download Binaries
Sources @ Bitbucket

Maven Artifact:

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>fontawesomefx</artifactId>
  <version>8.0.9</version>
</dependency>

How to get rid of focus highlighting in JavaFX

Today I was asked if I know a way to get rid of the focus-highlighting of JavaFX controls (respectively buttons):

button_hover

Most posts and tipps regarding this issue suggesting to adding:

.button:focused {
    -fx-focus-color: transparent; 
}

But with this style a glow like this is still left:

button_glow

To get rid of this glow also often suggested to play around with -fx-background-insets additionally:

.button:focused {
    -fx-focus-color: transparent; 
    -fx-background-insets: -1.4, 0, 1, 2;
}

But this results in a button rendered with out an outer border:

button_insets

Compared to the default button style

button

this is still a kind of “highlighting”:

Why is that? (And why are there actually 4 inset values ?)
(note he comment of David Grieve below)

Having a look at the JavaFX default style as defined by modena.css bares some more information:

/* A bright blue for the focus indicator of objects. Typically used as the
* first color in -fx-background-color for the "focused" pseudo-class. Also
* typically used with insets of -1.4 to provide a glowing effect.
*/
-fx-focus-color: #f25f29;
-fx-faint-focus-color: #f25f2933;

Obviously there is not only one focus color -fx-focus-color but also -fx-faint-focus-color which is meant to create this glow-effect (that is remaining when setting -fx-focus-color:transparent;).

A closer look at the .button:focused pseudo class (in modena.css):

.button:focused {
    -fx-background-color: -fx-faint-focus-color, -fx-focus-color, -fx-inner-border, -fx-body-color; 
    -fx-background-insets: -2, -0.3, 1, 2;
    -fx-background-radius: 7, 6, 4, 3;
}

Playing around with some (extreme ;-)) colouring reveals the arrangement:

.button:focused {
    -fx-focus-color: red;
    -fx-faint-focus-color: green;
    -fx-inner-border: blue;
    -fx-body-color: orange;

    -fx-background-color: -fx-faint-focus-color, -fx-focus-color, -fx-inner-border, -fx-body-color; 
    -fx-background-insets: -2, -0.3, 1, 2;
    -fx-background-radius: 7, 6, 4, 3;
}

button_hover_style

Getting back to the topic maybe a clent way to remove the focus hightlight is to use the default button styles also for .button:focus (same approach for other controls):

.button:focused {
    -fx-background-color: -fx-outer-border, -fx-inner-border, -fx-body-color; 
    -fx-background-insets: 0, 1, 2;
    -fx-background-radius: 5, 4, 3;
}

“somehow more organic”: how to create a ‘noisy’ gradient in JavaFX

If you always wondered why some regions on your Mac, Websites or in your Smartphone-Apps look somehow more organic than a plain coloured area or even an region with a gradient, have a closer look!
Zooming into these areas shows that they are a bit “noisy”.

This effect can be created very easily with CSS in JavaFX too:
I just noticed that “-fx-background-image” is painted in front of “-fx-background-color“:

javafx_css_color_paint

So, what is needed is a transparent “noise texture” which can be created here or here.

This texture is then used as a repeated background-image and painted in front the background-color which in JavaFX-CSS can also be a linear gradient:

-fx-background-color: linear-gradient(rgb(224,228,233) 0%, derive(rgb(224,228,233),-20%) 100%);
-fx-background-image: url("images/noise-texture.png");
-fx-background-repeat: repeat;  

I used this approach e.g in my MQTT.fx-UI:

mqtt-fx-6-noise-0.0.2

FontAwesomeFX: 4.0.1 support

Refer for latest updates here.

Hi,

I just have updated FontAwesomeFX to support currently released FontAwesome 4.0.1 with all of it’s 369 Icons.

Please note that some enum values have been changed, e.g. former AwesomeIcon.SIGNOUT is now AwesomeIcon.SIGN_OUT.

Also I have added some convenience methods to the helper class:

AwesomeDude.setIcon(TreeItem treeItem, AwesomeIcon icon) {
AwesomeDude.setIcon(TreeItem treeItem, AwesomeIcon icon, String iconSize)

Tip: Navigation Buttons

NavigationButtons

Add CSS and assign the class to a Button or ToggleButton:

.navigation-button{
    -fx-font-size: 0.9em;
    -fx-background-color: transparent;
    -fx-graphic-text-gap: 0px;
    -icons-color: gray;
    -fx-text-fill: gray;
    -fx-effect: innershadow( three-pass-box , rgba(0,0,0,0.4) , 6, 0.0 , 0 , 2 );
}

.navigation-button:pressed:hover{
    -icons-color: black;
    -fx-text-fill: black;
    -fx-effect: innershadow( three-pass-box , rgba(0,0,0,0.7) , 6, 0.0 , 0 , 2 );
}

.navigation-button:hover{
    -fx-effect: innershadow( three-pass-box , rgba(0,0,0,0.7) , 6, 0.0 , 0 , 2 );
}

Set FontAwesome-Icons:

AwesomeDude.setIcon(configurationButton, AwesomeIcon.GEAR, viewContext.getUiConfiguration().getIconEmSize(), ContentDisplay.TOP);
AwesomeDude.setIcon(aboutButton, AwesomeIcon.INFO, viewContext.getUiConfiguration().getIconEmSize(), ContentDisplay.TOP);
AwesomeDude.setIcon(exitButton, AwesomeIcon.SIGN_OUT, viewContext.getUiConfiguration().getIconEmSize(), ContentDisplay.TOP);

Source
@ Bitbucket

Maven

<dependency>
  <groupId>de.jensd</groupId>
  <artifactId>fontawesomefx</artifactId>
  <version>8.0.5</version>
</dependency>

Support for glyph font packs in ControlsFX 8.0.2
Since version 8.0.2 the ControlsFX-Project has support for glyph font packs.