Remove JNI, add JNA. Proof of concept.
This commit is contained in:
parent
e89cad31ef
commit
9d8ab59361
14 changed files with 220 additions and 190 deletions
|
@ -1,37 +0,0 @@
|
||||||
# Compiler
|
|
||||||
CC=gcc
|
|
||||||
# Flags
|
|
||||||
CFLAGS=-O2
|
|
||||||
MKDIR_P = mkdir -p
|
|
||||||
APP_NAME = mpvjni
|
|
||||||
|
|
||||||
all: x86 amd64
|
|
||||||
|
|
||||||
x86:
|
|
||||||
$(MKDIR_P) ./x86
|
|
||||||
$(CC) ${CFLAGS} -m32 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${APP_NAME}.c -o ${APP_NAME}_x86.o
|
|
||||||
$(CC) ${CFLAGS} -m32 -shared -fPIC -o ./x86/${APP_NAME}.so ${APP_NAME}_x86.o -lc
|
|
||||||
|
|
||||||
amd64:
|
|
||||||
$(MKDIR_P) ./amd64
|
|
||||||
$(CC) ${CFLAGS} -m64 -c -fPIC -I"${JAVA_HOME}/include" -I"${JAVA_HOME}/include/linux" ${APP_NAME}.c -o ${APP_NAME}_amd64.o
|
|
||||||
$(CC) ${CFLAGS} -m64 -shared -fPIC -o ./amd64/${APP_NAME}.so ${APP_NAME}_amd64.o -lc
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf \
|
|
||||||
${APP_NAME}_amd64.o \
|
|
||||||
${APP_NAME}_x86.o \
|
|
||||||
./x86 \
|
|
||||||
./amd64
|
|
||||||
|
|
||||||
headers:
|
|
||||||
cd /src/main/java
|
|
||||||
javac mplayer4anime/mpv/MpvJni.java -h ../../../mpv_library/
|
|
||||||
|
|
||||||
install: x86 amd64
|
|
||||||
install ./x86/${APP_NAME}.so ../src/main/resources/native/linux/x86/
|
|
||||||
install ./amd64/${APP_NAME}.so ../src/main/resources/native/linux/amd64/
|
|
||||||
|
|
||||||
uninstall:
|
|
||||||
rm ../src/main/resources/native/linux/x86/${APP_NAME}.so
|
|
||||||
rm ../src/main/resources/native/linux/amd64/${APP_NAME}.so
|
|
|
@ -1,21 +0,0 @@
|
||||||
/* DO NOT EDIT THIS FILE - it is machine generated */
|
|
||||||
#include <jni.h>
|
|
||||||
/* Header for class mplayer4anime_mpv_MpvSlave */
|
|
||||||
|
|
||||||
#ifndef _Included_mplayer4anime_mpv_MpvSlave
|
|
||||||
#define _Included_mplayer4anime_mpv_MpvSlave
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
/*
|
|
||||||
* Class: mplayer4anime_mpv_MpvSlave
|
|
||||||
* Method: play
|
|
||||||
* Signature: ()V
|
|
||||||
*/
|
|
||||||
JNIEXPORT void JNICALL Java_mplayer4anime_mpv_MpvSlave_play
|
|
||||||
(JNIEnv *, jobject);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
#endif
|
|
|
@ -1,6 +0,0 @@
|
||||||
#include <mpv/client.h>
|
|
||||||
#include "mplayer4anime_mpv_MpvSlave.h"
|
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_mplayer4anime_mpv_MpvSlave_play(JNIEnv * jnienv, jobject jobject){
|
|
||||||
|
|
||||||
};
|
|
5
pom.xml
5
pom.xml
|
@ -52,6 +52,11 @@
|
||||||
</issueManagement>
|
</issueManagement>
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
<dependency>
|
||||||
|
<groupId>net.java.dev.jna</groupId>
|
||||||
|
<artifactId>jna-platform</artifactId>
|
||||||
|
<version>5.6.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.google.code.gson</groupId>
|
<groupId>com.google.code.gson</groupId>
|
||||||
<artifactId>gson</artifactId>
|
<artifactId>gson</artifactId>
|
||||||
|
|
30
src/main/java/mplayer4anime/mpv/LibC.java
Normal file
30
src/main/java/mplayer4anime/mpv/LibC.java
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018-2021 Dmitry Isaenko
|
||||||
|
|
||||||
|
This file is part of mplayer4anime.
|
||||||
|
|
||||||
|
mplayer4anime is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
mplayer4anime is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with mplayer4anime. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package mplayer4anime.mpv;
|
||||||
|
|
||||||
|
import com.sun.jna.Library;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
|
||||||
|
public interface LibC extends Library {
|
||||||
|
LibC INSTANCE = Native.load("c", LibC.class);
|
||||||
|
|
||||||
|
int LC_NUMERIC = 1;
|
||||||
|
|
||||||
|
String setlocale(int localeType, String name);
|
||||||
|
}
|
37
src/main/java/mplayer4anime/mpv/LibMpv.java
Normal file
37
src/main/java/mplayer4anime/mpv/LibMpv.java
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018-2021 Dmitry Isaenko
|
||||||
|
|
||||||
|
This file is part of mplayer4anime.
|
||||||
|
|
||||||
|
mplayer4anime is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
mplayer4anime is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with mplayer4anime. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package mplayer4anime.mpv;
|
||||||
|
|
||||||
|
import com.sun.jna.Library;
|
||||||
|
import com.sun.jna.Native;
|
||||||
|
import com.sun.jna.ptr.IntByReference;
|
||||||
|
|
||||||
|
public interface LibMpv extends Library {
|
||||||
|
LibMpv INSTANCE = Native.load("libmpv", LibMpv.class);
|
||||||
|
|
||||||
|
long mpv_create();
|
||||||
|
int mpv_set_option_string(long ctx, String name, String data);
|
||||||
|
int mpv_set_option(long ctx, String name, int format, IntByReference data);
|
||||||
|
int mpv_initialize(long ctx);
|
||||||
|
int mpv_command(long ctx, String[] args);
|
||||||
|
|
||||||
|
|
||||||
|
mpv_event mpv_wait_event(long ctx, double timeout);
|
||||||
|
void mpv_terminate_destroy(long ctx);
|
||||||
|
}
|
|
@ -1,108 +0,0 @@
|
||||||
/*
|
|
||||||
Copyright 2018-2021 Dmitry Isaenko
|
|
||||||
|
|
||||||
This file is part of mplayer4anime.
|
|
||||||
|
|
||||||
mplayer4anime is free software: you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation, either version 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
mplayer4anime is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with mplayer4anime. If not, see <https://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package mplayer4anime.mpv;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.net.URISyntaxException;
|
|
||||||
import java.net.URL;
|
|
||||||
|
|
||||||
public final class MpvJniLibraryLoader {
|
|
||||||
private MpvJniLibraryLoader(){}
|
|
||||||
public static boolean load(){
|
|
||||||
String osName = System.getProperty("os.name").toLowerCase().replace(" ", "");
|
|
||||||
String osArch = System.getProperty("os.arch").toLowerCase().replace(" ", "");
|
|
||||||
String libPostfix = "so";
|
|
||||||
|
|
||||||
if (osName.equals("linux")){
|
|
||||||
switch (osArch){
|
|
||||||
case "i386":
|
|
||||||
case "i586":
|
|
||||||
case "i686":
|
|
||||||
osArch = "x86";
|
|
||||||
break;
|
|
||||||
case "x86_64":
|
|
||||||
case "amd64":
|
|
||||||
osArch = "amd64";
|
|
||||||
break;
|
|
||||||
// case "arm":
|
|
||||||
// osArch = "arm";
|
|
||||||
// break;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
final URL url_ = MpvJniLibraryLoader.class.getResource("/native/"+osName+"/"+osArch+"/mpvjni."+libPostfix);
|
|
||||||
if (url_ == null)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
String proto = url_.getProtocol();
|
|
||||||
|
|
||||||
File libraryFile;
|
|
||||||
if (proto.equals("file")){
|
|
||||||
// We can pick file from disk as is.
|
|
||||||
try {
|
|
||||||
libraryFile = new File(url_.toURI());
|
|
||||||
}
|
|
||||||
catch (URISyntaxException e){
|
|
||||||
e.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (proto.equals("jar")){
|
|
||||||
// We have to export file to temp dir.
|
|
||||||
InputStream inStream = MpvJniLibraryLoader.class.getResourceAsStream("/native/"+osName+"/"+osArch+"/mpvjni."+libPostfix);
|
|
||||||
if (inStream == null)
|
|
||||||
return false;
|
|
||||||
// Create temp folder
|
|
||||||
try{
|
|
||||||
File tmpDirFile = File.createTempFile("jni", null);
|
|
||||||
if (! tmpDirFile.delete())
|
|
||||||
return false;
|
|
||||||
if (! tmpDirFile.mkdirs())
|
|
||||||
return false;
|
|
||||||
libraryFile = new File(tmpDirFile, "mpvjni."+libPostfix);
|
|
||||||
byte[] ioBuffer = new byte[8192];
|
|
||||||
FileOutputStream foStream = new FileOutputStream(libraryFile);
|
|
||||||
while (inStream.read(ioBuffer) != -1)
|
|
||||||
foStream.write(ioBuffer);
|
|
||||||
foStream.close();
|
|
||||||
inStream.close();
|
|
||||||
libraryFile.deleteOnExit();
|
|
||||||
tmpDirFile.deleteOnExit();
|
|
||||||
}
|
|
||||||
catch (IOException ioe){
|
|
||||||
ioe.printStackTrace();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
return false;
|
|
||||||
|
|
||||||
//System.out.println("LIB LOCATION: "+libraryFile);
|
|
||||||
System.load(libraryFile.getAbsolutePath());
|
|
||||||
//System.out.println("LIB LOADED");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
104
src/main/java/mplayer4anime/mpv/MpvProcess.java
Normal file
104
src/main/java/mplayer4anime/mpv/MpvProcess.java
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018-2021 Dmitry Isaenko
|
||||||
|
|
||||||
|
This file is part of mplayer4anime.
|
||||||
|
|
||||||
|
mplayer4anime is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
mplayer4anime is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with mplayer4anime. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package mplayer4anime.mpv;
|
||||||
|
|
||||||
|
import com.sun.jna.ptr.IntByReference;
|
||||||
|
import mplayer4anime.ServiceWindow;
|
||||||
|
|
||||||
|
public class MpvProcess implements Runnable{
|
||||||
|
private String videoFilename;
|
||||||
|
private final LibC libC = LibC.INSTANCE;
|
||||||
|
private final LibMpv libMpv = LibMpv.INSTANCE;
|
||||||
|
|
||||||
|
/** MPV_FORMAT*/
|
||||||
|
private final int MPV_FORMAT_NONE = 0;
|
||||||
|
private final int MPV_FORMAT_STRING = 1;
|
||||||
|
private final int MPV_FORMAT_OSD_STRING = 2;
|
||||||
|
private final int MPV_FORMAT_FLAG = 3;
|
||||||
|
private final int MPV_FORMAT_INT64 = 4;
|
||||||
|
private final int MPV_FORMAT_DOUBLE = 5;
|
||||||
|
private final int MPV_FORMAT_NODE = 6;
|
||||||
|
private final int MPV_FORMAT_NODE_ARRAY = 7;
|
||||||
|
private final int MPV_FORMAT_NODE_MAP = 8;
|
||||||
|
private final int MPV_FORMAT_BYTE_ARRAY = 9;
|
||||||
|
|
||||||
|
/** mpv_event_id */
|
||||||
|
private final int MPV_EVENT_NONE = 0;
|
||||||
|
private final int MPV_EVENT_SHUTDOWN = 1;
|
||||||
|
private final int MPV_EVENT_LOG_MESSAGE = 2;
|
||||||
|
private final int MPV_EVENT_GET_PROPERTY_REPLY = 3;
|
||||||
|
private final int MPV_EVENT_SET_PROPERTY_REPLY = 4;
|
||||||
|
private final int MPV_EVENT_COMMAND_REPLY = 5;
|
||||||
|
private final int MPV_EVENT_START_FILE = 6;
|
||||||
|
private final int MPV_EVENT_END_FILE = 7;
|
||||||
|
private final int MPV_EVENT_FILE_LOADED = 8;
|
||||||
|
private final int MPV_EVENT_TRACKS_CHANGED = 9;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_TRACK_SWITCHED = 10;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_IDLE = 11;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_PAUSE = 12;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_UNPAUSE = 13;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_TICK = 14;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_SCRIPT_INPUT_DISPATCH = 15;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_CLIENT_MESSAGE = 16;
|
||||||
|
private final int MPV_EVENT_VIDEO_RECONFIG = 17;
|
||||||
|
private final int MPV_EVENT_AUDIO_RECONFIG = 18;
|
||||||
|
private final int MPV_EVENT_METADATA_UPDATE = 19;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_SEEK = 20;
|
||||||
|
private final int MPV_EVENT_PLAYBACK_RESTART = 21;
|
||||||
|
private final int MPV_EVENT_PROPERTY_CHANGE = 22;
|
||||||
|
private final int MPV_EVENT_CHAPTER_CHANGE = 23;//DEPRECATED
|
||||||
|
private final int MPV_EVENT_QUEUE_OVERFLOW = 24;
|
||||||
|
private final int MPV_EVENT_HOOK = 25;
|
||||||
|
|
||||||
|
MpvProcess(String filename){
|
||||||
|
this.videoFilename = filename;
|
||||||
|
libC.setlocale(LibC.LC_NUMERIC, "C"); //Somehow it's important
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (nonSupportedOs()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
long ctx = libMpv.mpv_create();
|
||||||
|
libMpv.mpv_set_option_string(ctx, "input-default-bindings", "yes");
|
||||||
|
libMpv.mpv_set_option_string(ctx, "input-vo-keyboard", "yes");
|
||||||
|
IntByReference value = new IntByReference(1);
|
||||||
|
libMpv.mpv_set_option(ctx, "osc", MPV_FORMAT_FLAG, value);
|
||||||
|
libMpv.mpv_initialize(ctx);
|
||||||
|
libMpv.mpv_command(ctx, new String[]{"loadfile", videoFilename, null});
|
||||||
|
while (true){
|
||||||
|
mpv_event event = libMpv.mpv_wait_event(ctx, 10000);
|
||||||
|
if (event.event_id == MPV_EVENT_SHUTDOWN)
|
||||||
|
break;
|
||||||
|
System.out.println(event.event_id);
|
||||||
|
}
|
||||||
|
libMpv.mpv_terminate_destroy(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean nonSupportedOs(){
|
||||||
|
if (! System.getProperty("os.name").toLowerCase().contains("linux")) {
|
||||||
|
ServiceWindow.getErrorNotification("Error",
|
||||||
|
"Non-Linux OS are not supported. Yet. Please yse mplayer backend for now.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,19 +19,10 @@
|
||||||
package mplayer4anime.mpv;
|
package mplayer4anime.mpv;
|
||||||
|
|
||||||
import mplayer4anime.ISlaveModeAppOrchestration;
|
import mplayer4anime.ISlaveModeAppOrchestration;
|
||||||
import mplayer4anime.ServiceWindow;
|
|
||||||
|
|
||||||
import java.util.ResourceBundle;
|
import java.util.ResourceBundle;
|
||||||
|
|
||||||
public class MpvSlave implements ISlaveModeAppOrchestration {
|
public class MpvSlave implements ISlaveModeAppOrchestration {
|
||||||
static {
|
|
||||||
if (! MpvJniLibraryLoader.load()){
|
|
||||||
ServiceWindow.getErrorNotification("Error",
|
|
||||||
"Unable to load mpv back end library. Please use mplayer instead"); // TODO: use bundle & translate
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
native void play();
|
|
||||||
|
|
||||||
public MpvSlave(ResourceBundle resourceBundle){
|
public MpvSlave(ResourceBundle resourceBundle){
|
||||||
|
|
||||||
|
@ -76,7 +67,9 @@ public class MpvSlave implements ISlaveModeAppOrchestration {
|
||||||
String subtitlesEncoding,
|
String subtitlesEncoding,
|
||||||
boolean subtitlesHidden,
|
boolean subtitlesHidden,
|
||||||
boolean isFullscreen) {
|
boolean isFullscreen) {
|
||||||
|
//TODO: fix
|
||||||
|
Thread thread = new Thread(new MpvProcess(VideoFile));
|
||||||
|
thread.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
33
src/main/java/mplayer4anime/mpv/mpv_event.java
Normal file
33
src/main/java/mplayer4anime/mpv/mpv_event.java
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
Copyright 2018-2021 Dmitry Isaenko
|
||||||
|
|
||||||
|
This file is part of mplayer4anime.
|
||||||
|
|
||||||
|
mplayer4anime is free software: you can redistribute it and/or modify
|
||||||
|
it under the terms of the GNU General Public License as published by
|
||||||
|
the Free Software Foundation, either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
mplayer4anime is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU General Public License
|
||||||
|
along with mplayer4anime. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package mplayer4anime.mpv;
|
||||||
|
|
||||||
|
import com.sun.jna.Structure;
|
||||||
|
import com.sun.jna.Structure.FieldOrder;
|
||||||
|
import com.sun.jna.ptr.IntByReference;
|
||||||
|
|
||||||
|
@FieldOrder({"event_id","error","reply_userdata","data"})
|
||||||
|
public class mpv_event extends Structure {
|
||||||
|
public mpv_event(){}
|
||||||
|
|
||||||
|
public int event_id;
|
||||||
|
public int error;
|
||||||
|
public long reply_userdata; // long replaced originally uint64_t
|
||||||
|
public IntByReference data;
|
||||||
|
}
|
|
@ -18,12 +18,12 @@
|
||||||
<children>
|
<children>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openDirChooser">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openDirChooser">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M10,4L12,6H20A2,2 0 0,1 22,8V18A2,2 0 0,1 20,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10M15,9V12H12V14H15V17H17V14H20V12H17V9H15Z" />
|
<SVGPath content="M10,4L12,6H20A2,2 0 0,1 22,8V18A2,2 0 0,1 20,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10M15,9V12H12V14H15V17H17V14H20V12H17V9H15Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openFilesChooser">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openFilesChooser">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M14,10H19.5L14,4.5V10M5,3H15L21,9V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3M9,18H11V15H14V13H11V10H9V13H6V15H9V18Z" />
|
<SVGPath content="M14,10H19.5L14,4.5V10M5,3H15L21,9V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3M9,18H11V15H14V13H11V10H9V13H6V15H9V18Z" fill="#1a1a1a" />
|
||||||
</graphic></Button>
|
</graphic></Button>
|
||||||
<Pane minWidth="5.0" HBox.hgrow="NEVER" />
|
<Pane minWidth="5.0" HBox.hgrow="NEVER" />
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#cleanList">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#cleanList">
|
||||||
|
@ -36,12 +36,12 @@
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
<Pane HBox.hgrow="ALWAYS" />
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" />
|
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
|
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del">
|
||||||
|
|
|
@ -19,12 +19,12 @@
|
||||||
<children>
|
<children>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openDirChooser">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openDirChooser">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M10,4L12,6H20A2,2 0 0,1 22,8V18A2,2 0 0,1 20,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10M15,9V12H12V14H15V17H17V14H20V12H17V9H15Z" />
|
<SVGPath content="M10,4L12,6H20A2,2 0 0,1 22,8V18A2,2 0 0,1 20,20H4C2.89,20 2,19.1 2,18V6C2,4.89 2.89,4 4,4H10M15,9V12H12V14H15V17H17V14H20V12H17V9H15Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openFilesChooser">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#openFilesChooser">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M14,10H19.5L14,4.5V10M5,3H15L21,9V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3M9,18H11V15H14V13H11V10H9V13H6V15H9V18Z" />
|
<SVGPath content="M14,10H19.5L14,4.5V10M5,3H15L21,9V19A2,2 0 0,1 19,21H5C3.89,21 3,20.1 3,19V5C3,3.89 3.89,3 5,3M9,18H11V15H14V13H11V10H9V13H6V15H9V18Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Pane minWidth="5.0" />
|
<Pane minWidth="5.0" />
|
||||||
|
@ -39,12 +39,12 @@
|
||||||
<Pane HBox.hgrow="ALWAYS" />
|
<Pane HBox.hgrow="ALWAYS" />
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Up">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" />
|
<SVGPath content="M7.41,15.41L12,10.83L16.59,15.41L18,14L12,8L6,14L7.41,15.41Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Down">
|
||||||
<graphic>
|
<graphic>
|
||||||
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" />
|
<SVGPath content="M7.41,8.58L12,13.17L16.59,8.58L18,10L12,16L6,10L7.41,8.58Z" fill="#1a1a1a" />
|
||||||
</graphic>
|
</graphic>
|
||||||
</Button>
|
</Button>
|
||||||
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del">
|
<Button minHeight="28.0" mnemonicParsing="false" onAction="#Del">
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Loading…
Reference in a new issue