Skip to content

Commit 62f46e8

Browse files
committed
Release 1.0.9: add palette icons and click insert
Made-with: Cursor
1 parent 12c7d99 commit 62f46e8

24 files changed

Lines changed: 316 additions & 14 deletions

‎README.md‎

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ git clone https://github.com/code4teaching/VisuStruct.git
2222

2323
---
2424

25+
## Changes in 1.0.9 (summary)
26+
27+
- **Palette:** Lucide SVG icons on the element buttons, including `split` for Branch.
28+
- **For loop:** multi-line start/condition/increment headers are shown and exported as `start; condition; increment`.
29+
- **Java export:** `output:` statements become `System.out.println(...)`.
30+
31+
Full notes: [`release-notes/v1.0.9.md`](release-notes/v1.0.9.md).
32+
2533
## Changes in 1.0.8 (summary)
2634

2735
- **Code generator:** **JavaScript** target (brace syntax like Java, `"use strict";` prefix); **`celanguage`** `2` = JavaScript in **`visustruct.properties`** (with `0` = Java, `1` = Python).
@@ -85,7 +93,7 @@ This release aligns **branding and technical identity** with **VisuStruct**. **`
8593
- **Java 17** target (build and run with JDK 17+).
8694
- **FlatLaf** light/dark themes; **JDOM2**; no legacy AppleJavaExtensions.
8795
- **Motif** look-and-feel removed; **Metal** and FlatLaf available.
88-
- Current fat JAR name follows **`pom.xml`** **`version`** (e.g. **`visustruct-1.0.8.jar`**).
96+
- Current fat JAR name follows **`pom.xml`** **`version`** (e.g. **`visustruct-1.0.9.jar`**).
8997

9098
---
9199

@@ -109,7 +117,7 @@ On **Windows**, double-click often works if `.jar` is associated with Java. If a
109117

110118
All releases: [github.com/code4teaching/VisuStruct/releases](https://github.com/code4teaching/VisuStruct/releases)
111119

112-
**Maintainers:** To ship a new version, create a GitHub **Release** with a tag such as **`v1.0.8`**. Workflow [`.github/workflows/release-assets.yml`](.github/workflows/release-assets.yml) builds the JARs and attaches **`visustruct.jar`** (stable download URL above).
120+
**Maintainers:** To ship a new version, create a GitHub **Release** with a tag such as **`v1.0.9`**. Workflow [`.github/workflows/release-assets.yml`](.github/workflows/release-assets.yml) builds the JARs and attaches **`visustruct.jar`** (stable download URL above).
113121

114122
---
115123

@@ -160,13 +168,13 @@ chmod +x mvnw
160168
Output (version from `pom.xml`):
161169

162170
```text
163-
target/visustruct-1.0.8.jar
171+
target/visustruct-1.0.9.jar
164172
```
165173

166174
## Run
167175

168176
```bash
169-
java -jar target/visustruct-1.0.8.jar
177+
java -jar target/visustruct-1.0.9.jar
170178
```
171179

172180
Double-click may work if `.jar` is associated with Java.
@@ -186,6 +194,8 @@ New **visible UI strings** belong in **`Messages*.properties`** (and **`structur
186194

187195
**MIT** — see [LICENSE](LICENSE). Copyright to the original codebase remains with **Kevin Krummenauer** (also stated in LICENSE).
188196

197+
Palette icons are from [Lucide](https://lucide.dev/) (ISC; some icons derived from Feather/MIT). The bundled license text is in `src/main/resources/licenses/LUCIDE.txt`.
198+
189199
## Historical upstream website (attribution)
190200

191201
[whiledo.de — Struktogrammeditor](https://whiledo.de/index.php?p=struktogrammeditor) — original editor by Kevin Krummenauer (context and license lineage; **install VisuStruct** from this GitHub project instead).

‎docs/VisuStruct-icon.png‎

262 KB
Loading

‎packaging/macos/build-lightweight-app.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
set -euo pipefail
55
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
66
ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
7-
VER="${PROJECT_VERSION:-1.0.8}"
7+
VER="${PROJECT_VERSION:-1.0.9}"
88
JAR_NAME="visustruct-${VER}.jar"
99
OUT="${ROOT}/dist/macos-app-light"
1010
APP="${OUT}/VisuStruct.app"

‎packaging/macos/build-macos-app.sh‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# Voraussetzung: JDK 17+ mit jpackage (im PATH oder JAVA_HOME).
55
set -euo pipefail
66
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
7-
VER="${PROJECT_VERSION:-1.0.8}"
7+
VER="${PROJECT_VERSION:-1.0.9}"
88
JAR="visustruct-${VER}.jar"
99
INPUT="${ROOT}/target"
1010
OUT="${ROOT}/dist/macos-app"

‎pom.xml‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>de.visustruct</groupId>
66
<artifactId>visustruct</artifactId>
7-
<version>1.0.8</version>
7+
<version>1.0.9</version>
88
<name>VisuStruct</name>
99

1010
<properties>
@@ -29,6 +29,11 @@
2929
<artifactId>flatlaf</artifactId>
3030
<version>3.7.1</version>
3131
</dependency>
32+
<dependency>
33+
<groupId>com.formdev</groupId>
34+
<artifactId>flatlaf-extras</artifactId>
35+
<version>3.7.1</version>
36+
</dependency>
3237
</dependencies>
3338

3439
<build>

‎release-notes/v1.0.9.md‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# VisuStruct 1.0.9 — release notes
2+
3+
- **Palette:** Lucide SVG icons for the element buttons (`Statement`, `Branch`, loops, `Switch`, `Break`, `Call`).
4+
- **For loop:** multi-part headers are displayed and generated as a single C-style header (`start; condition; increment`).
5+
- **Java code generation:** `output:` statements are exported as `System.out.println(...)`.
6+
- **Licenses:** Lucide attribution added to the About dialog; full Lucide/Feather license text is bundled.
7+
8+
Build artifact: **`visustruct-1.0.9.jar`**.

‎src/main/java/de/visustruct/control/Controlling.java‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ public Struktogramm gibAktuellesStruktogramm(){
180180
return gui.gibTabbedpane().gibAktuellesStruktogramm();
181181
}
182182

183+
public void paletteElementEinfuegen(int typ){
184+
Struktogramm str = gibAktuellesStruktogramm();
185+
if (str != null){
186+
str.neuesElementAnAktuellerStelleEinfuegen(typ);
187+
gui.gibTabbedpane().requestFocusInWindow();
188+
}
189+
}
190+
183191

184192

185193
public Struktogramm neuesStruktogramm(){
@@ -443,6 +451,7 @@ public void showInfo(){
443451
final String projektUrl = "https://github.com/code4teaching/VisuStruct";
444452
final String webUrl = "https://www.sebastiao.org/";
445453
final String originalUrl = "https://github.com/kekru/struktogrammeditor";
454+
final String lucideUrl = "https://lucide.dev/";
446455

447456
String html = "<html><body style=\"font-family:sans-serif;font-size:11pt;\">"
448457
+ "<p style=\"margin-top:0;margin-bottom:10px;\"><b>"
@@ -454,6 +463,9 @@ public void showInfo(){
454463
+ "<p style=\"margin-bottom:6px;\"><b>Acknowledgement</b></p>"
455464
+ "<p style=\"margin-top:0;\"><b>VisuStruct</b> builds on the open-source structure chart editor by Kevin Krummenauer (MIT).<br/>"
456465
+ "Prior source: <a href=\"" + originalUrl + "\">kekru/struktogrammeditor</a> on GitHub.</p>"
466+
+ "<p style=\"margin-top:0;\">Palette icons: <a href=\"" + lucideUrl + "\">Lucide Icons</a> "
467+
+ "(ISC License; some icons derived from Feather/MIT).<br/>"
468+
+ "License text is included in <code>licenses/LUCIDE.txt</code>.</p>"
457469
+ "</body></html>";
458470

459471
JEditorPane pane = new JEditorPane("text/html", html);

‎src/main/java/de/visustruct/control/Struktogramm.java‎

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,9 @@ public class Struktogramm extends JPanel implements MouseListener, MouseMotionLi
8383
private boolean popupmenuSichtbar = false;
8484
/** Zuletzt bekannte Mausposition auf der Zeichenfläche (für Einfügen, wenn der Zeiger schon in Menüleiste etc. ist). */
8585
private Point letzteDiagrammMausKoords;
86+
/** Festes Ziel nach einem Klick in den Canvas; bleibt erhalten, während die Maus zur Palette wandert. */
87+
private Point ausgewaehlteEinfuegeKoords;
88+
private Rectangle ausgewaehlteEinfuegeMarkierung;
8689
//private JScrollPane scrollpane; //in diesem JScrollPane liegt das Struktogramm, scrollpane liegt wiederrum in einem JTabbedPane (siehe GUI)
8790
private StrTabbedPane tabbedpane; //für eine kennt-Beziehung mit dem JTabbedPane
8891
private Dimension dimGroesse; //Ausmaße des Struktogramms
@@ -353,6 +356,12 @@ public void zeichne(Graphics panelGraphics){
353356
g.fillRect(rectVorschau.x,rectVorschau.y,rectVorschau.width,rectVorschau.height);
354357
}
355358

359+
if (ausgewaehlteEinfuegeMarkierung != null){
360+
g.setColor(CanvasStyle.getDropPreview());
361+
g.fillRect(ausgewaehlteEinfuegeMarkierung.x, ausgewaehlteEinfuegeMarkierung.y,
362+
ausgewaehlteEinfuegeMarkierung.width, ausgewaehlteEinfuegeMarkierung.height);
363+
}
364+
356365

357366
if (dragZwischenlagerElement != null){//wenn gerade ein Element aus dem Struktogramm gezogen wird...
358367
Rectangle rectDragElement = dragZwischenlagerElement.gibRectangle();
@@ -609,8 +618,30 @@ public StruktogrammElement neuesStruktogrammElement(int typ){
609618
* Wird in KeyReleased in Controlling genutzt
610619
*/
611620
public void neuesElementAnAktuellerStelleEinfuegen(int typ){
612-
Point p = getMousePosition();
613-
gezogenesElementEinfuegen(p.x, p.y, typ);
621+
Point p = ausgewaehlteEinfuegeKoords;
622+
if (p == null) {
623+
p = getMousePosition();
624+
}
625+
if (p == null) {
626+
p = letzteDiagrammMausKoords;
627+
}
628+
if (p != null && liste.gibElementAnPos(p.x, p.y, true) != null) {
629+
gezogenesElementEinfuegen(p.x, p.y, typ);
630+
} else {
631+
neuesElementAmEndeEinfuegen(typ);
632+
}
633+
}
634+
635+
private void neuesElementAmEndeEinfuegen(int typ){
636+
StruktogrammElement neues = neuesStruktogrammElement(typ);
637+
638+
if (neues != null){
639+
liste.hinzufuegen(neues);
640+
einfuegeMarkierungLoeschen();
641+
zeichenbereichAktualisieren();
642+
zeichne();
643+
rueckgaengigPunktSetzen();
644+
}
614645
}
615646

616647
/**
@@ -678,7 +709,7 @@ private void elementEinfuegen(int x, int y, StruktogrammElement neues, Struktogr
678709
listeZumEinfuegen.hinzufuegen(listeNeue,tmp,oberhalbEinfuegen);
679710
}
680711

681-
rectVorschau = null; //die rote Vorschau wird beendet
712+
einfuegeMarkierungLoeschen(); //die rote Vorschau wird beendet
682713

683714
zeichenbereichAktualisieren(); //da etwas in der Struktur des Struktogramms verändert wurde, muss der Zeichenbereich aktualisiert werden...
684715
zeichne();
@@ -1212,13 +1243,35 @@ public void mousePressed(MouseEvent e){
12121243
public void mouseClicked(MouseEvent e){
12131244
letzteDiagrammMausKoords = new Point(e.getX(), e.getY());
12141245
if (SwingUtilities.isLeftMouseButton(e)) { // linke Maustaste
1246+
einfuegeZielSetzen(e.getX(), e.getY());
1247+
vorschauMarkierungAnzeigen(e.getX(), e.getY(), false);
12151248
elementAnPosBefuellen(e.getX(), e.getY()); // EingabeDialog öffnen
12161249
zeichne();
12171250
} else if (SwingUtilities.isRightMouseButton(e)) { // rechte Maustaste
12181251
popupMenueZeigen(e.getX(), e.getY()); // Popup-Menü zeigen
12191252
}
12201253
}
12211254

1255+
private void einfuegeZielSetzen(int x, int y){
1256+
ausgewaehlteEinfuegeKoords = new Point(x, y);
1257+
StruktogrammElementListe zielListe = (StruktogrammElementListe)liste.gibElementAnPos(x, y, true);
1258+
if (zielListe != null) {
1259+
ausgewaehlteEinfuegeMarkierung = new Rectangle(zielListe.gibRectangle());
1260+
return;
1261+
}
1262+
1263+
StruktogrammElement zielElement = (StruktogrammElement)liste.gibElementAnPos(x, y, false);
1264+
ausgewaehlteEinfuegeMarkierung = zielElement != null
1265+
? zielElement.gibVorschauRect(ausgewaehlteEinfuegeKoords)
1266+
: null;
1267+
}
1268+
1269+
private void einfuegeMarkierungLoeschen(){
1270+
rectVorschau = null;
1271+
ausgewaehlteEinfuegeKoords = null;
1272+
ausgewaehlteEinfuegeMarkierung = null;
1273+
}
1274+
12221275

12231276

12241277

‎src/main/java/de/visustruct/struktogrammelemente/Anweisung.java‎

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import de.visustruct.control.GlobalSettings;
77
import de.visustruct.control.Struktogramm;
88
import de.visustruct.other.JTextAreaEasy;
9+
import de.visustruct.view.CodeErzeuger;
910

1011

1112
public class Anweisung extends StruktogrammElement {
@@ -28,12 +29,40 @@ public void quellcodeGenerieren(int typ, int anzahlEingerueckt, int anzahlEinzur
2829
String zeile;
2930
if (alsKommentar) {
3031
zeile = wandleZuAusgabe(co("kommentar") + co("text") + co("kommentarzu") + "\n", typ, anzahlEingerueckt, true)
31-
+ wandleZuAusgabe(co("text"), typ, anzahlEingerueckt, false);
32+
+ generiereAnweisungscode(typ, anzahlEingerueckt);
3233
} else {
33-
zeile = wandleZuAusgabe(co("kommentar") + co("text") + co("kommentarzu"), typ, anzahlEingerueckt, false);
34+
zeile = generiereAnweisungscode(typ, anzahlEingerueckt);
3435
}
3536
textarea.hinzufuegen(zeile + "\n");
3637
}
38+
39+
private String generiereAnweisungscode(int typ, int anzahlEingerueckt){
40+
if (typ != CodeErzeuger.typJava) {
41+
return wandleZuAusgabe(co("text"), typ, anzahlEingerueckt, false);
42+
}
43+
44+
StringBuilder code = new StringBuilder();
45+
for (int i = 0; i < text.length; i++) {
46+
if (i > 0) {
47+
code.append('\n');
48+
}
49+
code.append(einruecken(generiereJavaAnweisungszeile(text[i]), anzahlEingerueckt));
50+
}
51+
return code.toString();
52+
}
53+
54+
private String generiereJavaAnweisungszeile(String eingabe){
55+
String zeile = eingabe != null ? eingabe.trim() : "";
56+
if (zeile.regionMatches(true, 0, "output:", 0, "output:".length())) {
57+
String ausdruck = zeile.substring("output:".length()).trim();
58+
if (ausdruck.endsWith(";")) {
59+
ausdruck = ausdruck.substring(0, ausdruck.length() - 1).trim();
60+
}
61+
return "System.out.println(" + ausdruck + ");";
62+
}
63+
64+
return eingabe != null ? eingabe : "";
65+
}
3766

3867

3968

‎src/main/java/de/visustruct/struktogrammelemente/ForSchleife.java‎

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,53 @@
88
import de.visustruct.view.CodeErzeuger;
99

1010
public class ForSchleife extends WhileSchleife { //erbt von WhileSchleife
11+
private static final String KOPF_TRENNER = "; ";
1112

1213
public ForSchleife(Graphics2D g){
1314
super(g);
1415

1516
setzeText(GlobalSettings.gibElementBeschriftung(Struktogramm.typForSchleife));
1617
}
18+
19+
@Override
20+
protected void randGroesseSetzen(){
21+
if (hatMehrteiligenKopf()){
22+
setObererRand(obererRandZusatz + gibTexthoehe(text[0]));
23+
}else{
24+
super.randGroesseSetzen();
25+
}
26+
}
27+
28+
@Override
29+
protected int gibBreiteDerBreitestenTextzeile(){
30+
if (hatMehrteiligenKopf()){
31+
return gibTextbreite(gibKopfText());
32+
}
33+
34+
return super.gibBreiteDerBreitestenTextzeile();
35+
}
36+
37+
@Override
38+
protected void textZeichnen(){
39+
if (!hatMehrteiligenKopf()){
40+
super.textZeichnen();
41+
return;
42+
}
43+
44+
String kopfText = gibKopfText();
45+
int texthoehe = gibTexthoehe(text[0]);
46+
47+
g.setColor(getFarbeSchrift());
48+
g.drawString(kopfText, gibX() + gibXVerschiebungFuerTextInMitte(kopfText), gibY() + texthoehe - 5);
49+
}
50+
51+
private boolean hatMehrteiligenKopf(){
52+
return text != null && text.length > 1;
53+
}
54+
55+
private String gibKopfText(){
56+
return String.join(KOPF_TRENNER, text);
57+
}
1758

1859

1960
@Override //siehe DoUntilSchleife
@@ -25,6 +66,9 @@ public void quellcodeGenerieren(int typ, int anzahlEingerueckt, int anzahlEinzur
2566
if (typ == CodeErzeuger.typPython) {
2667
vorher = quellcodeMitKommentarVorspann("for ", ":\n", typ, anzahlEingerueckt, alsKommentar);
2768
nachher = "";
69+
} else if (hatMehrteiligenKopf()) {
70+
vorher = quellcodeMitKommentarVorspann("for(", "){\n", gibKopfText(), typ, anzahlEingerueckt, alsKommentar);
71+
nachher = "}\n";
2872
} else {
2973
vorher = quellcodeMitKommentarVorspann("for(", "){\n", typ, anzahlEingerueckt, alsKommentar);
3074
nachher = "}\n";
@@ -37,5 +81,15 @@ public void quellcodeGenerieren(int typ, int anzahlEingerueckt, int anzahlEinzur
3781
}
3882

3983
}
84+
85+
private String quellcodeMitKommentarVorspann(String linkerTeil, String rechterTeil, String codeText, int typ,
86+
int anzahlEingerueckt, boolean alsKommentar) {
87+
StringBuilder sb = new StringBuilder();
88+
if (alsKommentar) {
89+
sb.append(wandleZuAusgabe(co("kommentar") + co("text") + co("kommentarzu") + "\n", typ, anzahlEingerueckt, true));
90+
}
91+
sb.append(einruecken(linkerTeil + codeText + rechterTeil, anzahlEingerueckt));
92+
return sb.toString();
93+
}
4094

4195
}

0 commit comments

Comments
 (0)