init commit

This commit is contained in:
Dominik Krenn 2025-09-19 11:41:24 +02:00
commit 1427029da0
7 changed files with 392 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
build/
*.class

10
Main.java Normal file
View File

@ -0,0 +1,10 @@
import src.Application;
public class Main {
public static void main(String[] args)
{
Application app = new Application();
app.run();
}
}

210
run.sh Executable file
View File

@ -0,0 +1,210 @@
#!/usr/bin/env bash
set -e
APP_NAME="calci"
BUILD_DIR="build"
MAIN_CLASS="Main"
USE_UI=0
IGNORE_PATTERNS=()
########################################
# USER-FACING (CLI surface)
########################################
print_help() {
cat <<EOF
$APP_NAME runner
Usage: ./run.sh [options]
Options:
--main <Class> Set the main class to run (default: Main)
--ui Enable JavaFX modules (tries to auto-detect JAVAFX_HOME)
--ignore a|b|c Ignore files/dirs (split by |) when copying resources
--help Show this help message
EOF
}
########################################
# BACKEND (work logic)
########################################
compile_sources() {
echo "🛠️ Compiling sources..."
if [ $USE_UI -eq 1 ]; then
detect_javafx
javac --module-path "$JAVAFX_HOME/lib" \
--add-modules javafx.controls,javafx.fxml,javafx.swing \
-d "$BUILD_DIR" $(find src -name "*.java")
else
javac -d "$BUILD_DIR" $(find src -name "*.java")
fi
}
copy_resources() {
echo "📦 Copying resources..."
# Build rsync exclude flags
local excludes=( "--exclude=*.java" )
for pat in "${IGNORE_PATTERNS[@]}"; do
excludes+=( "--exclude=$pat" )
done
rsync -a "${excludes[@]}" ./ "$BUILD_DIR"/
}
run_app() {
echo "🚀 Running $MAIN_CLASS..."
if [ $USE_UI -eq 1 ]; then
java --module-path "$JAVAFX_HOME/lib" \
--add-modules javafx.controls,javafx.fxml,javafx.swing \
-cp "$BUILD_DIR" "$MAIN_CLASS"
else
java -cp "$BUILD_DIR" "$MAIN_CLASS"
fi
}
detect_javafx() {
if [ -n "$JAVAFX_HOME" ]; then
return
fi
echo "🔍 Trying to auto-detect JavaFX SDK..."
for path in \
"/usr/share/openjfx" \
"/usr/share/java/openjfx" \
"/usr/lib/jvm/javafx-sdk-21" \
"/usr/lib/jvm/javafx-sdk-17" \
"$HOME/javafx-sdk-21" \
"$HOME/javafx-sdk-17"; do
if [ -d "$path/lib" ]; then
JAVAFX_HOME="$path"
echo "✅ Found JavaFX SDK at $JAVAFX_HOME"
return
fi
done
ask_user_install_javafx
if [ ! -d "$JAVAFX_HOME/lib" ]; then
echo "Warning: Installed JavaFX but still cannot find lib/. Please set JAVAFX_HOME manually."
exit 1
fi
}
########################################
# HELPERS (system checks, installs)
########################################
ask_install() {
local tool=$1
if ! command -v "$tool" >/dev/null 2>&1; then
echo "Error: $tool is not installed."
read -rp "Do you want to install $tool now? (y/n) " choice
case "$choice" in
y|Y)
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y default-jdk
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y java-17-openjdk-devel
elif command -v pacman >/dev/null 2>&1; then
sudo pacman -S --noconfirm jdk-openjdk
else
echo "Package manager not supported, please install $tool manually."
exit 1
fi
;;
*) exit 1 ;;
esac
fi
}
try_install_javafx() {
if command -v apt-get >/dev/null 2>&1; then
sudo apt-get update && sudo apt-get install -y openjfx
JAVAFX_HOME="/usr/share/openjfx"
elif command -v dnf >/dev/null 2>&1; then
sudo dnf install -y openjfx
JAVAFX_HOME="/usr/share/openjfx"
elif command -v pacman >/dev/null 2>&1; then
sudo pacman -S --noconfirm javafx21-openjdk
JAVAFX_HOME="/usr/lib/jvm/javafx-sdk-21"
else
return 1
fi
return 0
}
ask_user_install_javafx() {
echo "❌ Could not find JavaFX SDK."
read -rp "Do you want to install JavaFX now? (y/n) " choice
case "$choice" in
y|Y)
try_install_javafx || ask_user_custom_command
;;
*)
echo "Please install JavaFX manually and set JAVAFX_HOME."
exit 1
;;
esac
}
ask_user_custom_command() {
echo "⚠️ No supported package manager detected."
read -rp "Do you want to enter a custom install command? (y/n) " custom
case "$custom" in
y|Y)
read -rp "Enter install command: " cmd
if [ -n "$cmd" ]; then
echo "Running: $cmd"
if ! eval "$cmd"; then
echo "❌ Installation command failed."
exit 1
fi
else
echo "No command entered. Aborting."
exit 1
fi
;;
*)
echo "Please download JavaFX manually:"
echo "👉 https://gluonhq.com/products/javafx/"
exit 1
;;
esac
}
########################################
# ENTRYPOINT
########################################
while [[ $# -gt 0 ]]; do
case "$1" in
--main)
MAIN_CLASS="$2"
shift 2
;;
--ui)
USE_UI=1
shift
;;
--ignore)
IFS='|' read -ra IGNORE_PATTERNS <<< "$2"
shift 2
;;
--help)
print_help
exit 0
;;
*)
echo "Unknown option: $1"
print_help
exit 1
;;
esac
done
ask_install javac
ask_install java
mkdir -p "$BUILD_DIR"
compile_sources
copy_resources
run_app

3
sources.txt Normal file
View File

@ -0,0 +1,3 @@
src/Base.java
src/Application.java
Main.java

25
src/Application.java Normal file
View File

@ -0,0 +1,25 @@
package src;
import javafx.fxml.FXML;
public class Application extends Base {
public Application() {
super("Hello FXML", 675, 600);
}
@FXML
private void sayHello() {
System.out.println("Hello from FXML!");
}
protected void on_button_click(String label) {
System.out.println("Button clicked: " + label);
}
@Override
public void initUi() {
loadUi("./hello.fxml");
}
}

82
src/Base.java Normal file
View File

@ -0,0 +1,82 @@
package src;
import javafx.embed.swing.JFXPanel;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.event.ActionEvent;
import javafx.scene.input.MouseEvent;
import javax.swing.*;
import java.awt.*;
import java.io.IOException;
import java.net.URL;
public abstract class Base {
private final JFrame frame;
private final int width;
private final int height;
private final String title;
public Base(String title, int width, int height) {
this.title = title;
this.width = width;
this.height = height;
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(width, height);
frame.setResizable(false);
JFXPanel fxPanel = new JFXPanel();
frame.add(fxPanel, BorderLayout.CENTER);
}
public void run() {
initUi();
SwingUtilities.invokeLater(() -> frame.setVisible(true));
}
public abstract void initUi();
protected abstract void on_button_click(String label);
@FXML
protected void button_click(MouseEvent e) {
if (e.getSource() instanceof Button btn) {
on_button_click(btn.getText());
}
}
protected void loadUi(String fxmlPath) {
SwingUtilities.invokeLater(() -> {
try {
String resolvedPath;
if (fxmlPath.startsWith("./")) {
resolvedPath = "/src/views" + fxmlPath.substring(1);
} else {
resolvedPath = fxmlPath.startsWith("/") ? fxmlPath : "/" + fxmlPath;
}
JFXPanel fxPanel = (JFXPanel) frame.getContentPane().getComponent(0);
URL url = getClass().getResource(resolvedPath);
if (url == null) {
throw new IllegalStateException("FXML not found: " + resolvedPath);
}
FXMLLoader loader = new FXMLLoader(url);
loader.setController(this);
Parent root = loader.load();
javafx.application.Platform.runLater(() -> {
Scene scene = new Scene(root, width, height);
fxPanel.setScene(scene);
});
} catch (IOException e) {
e.printStackTrace();
}
});
}
}

60
src/views/hello.fxml Executable file
View File

@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TitledPane?>
<?import javafx.scene.layout.ColumnConstraints?>
<?import javafx.scene.layout.GridPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.layout.RowConstraints?>
<?import javafx.scene.layout.VBox?>
<TitledPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="600.0" prefWidth="675.0" xmlns="http://javafx.com/javafx/24.0.1" xmlns:fx="http://javafx.com/fxml/1">
<content>
<VBox maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="450.0" prefWidth="600.0">
<children>
<Label fx:id="label" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="80.0" prefWidth="584.0" text="Label" />
<HBox prefHeight="450.0" prefWidth="675.0">
<children>
<GridPane maxWidth="1.7976931348623157E308" prefHeight="282.0" prefWidth="595.0">
<columnConstraints>
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
<ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" prefWidth="100.0" />
</columnConstraints>
<rowConstraints>
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
<RowConstraints minHeight="10.0" prefHeight="30.0" vgrow="SOMETIMES" />
</rowConstraints>
<children>
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="Button" GridPane.rowIndex="1" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="8" GridPane.columnIndex="1" GridPane.rowIndex="1" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="9" GridPane.columnIndex="2" GridPane.rowIndex="1" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" prefHeight="0.0" prefWidth="100.0" text="+" GridPane.columnIndex="3" GridPane.rowIndex="1" GridPane.rowSpan="2" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="4" GridPane.rowIndex="2" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="5" GridPane.columnIndex="1" GridPane.rowIndex="2" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="7" GridPane.rowIndex="1" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="6" GridPane.columnIndex="2" GridPane.rowIndex="2" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="1" GridPane.rowIndex="3" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="2" GridPane.columnIndex="1" GridPane.rowIndex="3" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="3" GridPane.columnIndex="2" GridPane.rowIndex="3" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="=" GridPane.columnIndex="3" GridPane.rowIndex="3" GridPane.rowSpan="2" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="0" GridPane.rowIndex="4" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="." GridPane.columnIndex="1" GridPane.rowIndex="4" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="+/-" GridPane.columnIndex="2" GridPane.rowIndex="4" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="CLR" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="/" GridPane.columnIndex="1" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="*" GridPane.columnIndex="2" />
<Button maxHeight="1.7976931348623157E308" maxWidth="1.7976931348623157E308" mnemonicParsing="false" onMouseClicked="#button_click" text="-" GridPane.columnIndex="3" />
</children>
</GridPane>
</children>
</HBox>
</children>
</VBox>
</content>
</TitledPane>