initial
This commit is contained in:
26
README.md
Normal file
26
README.md
Normal file
@@ -0,0 +1,26 @@
|
||||
# Simple Ontology
|
||||
## Define some truth !
|
||||
**Create custom node network graphs aka ontologies.**
|
||||
Tool to make ontological network topologies with.
|
||||
Has saving and reopening functionality and exports images.
|
||||
Smallest alternative to protégé, ONTOLIS or OntoStudio.
|
||||
|
||||
**How to use**
|
||||
Add nodes by clicking on "Add Node".
|
||||
Select a node by clicking on it and type on your keyboard to give it a title / rename it.
|
||||
Link nodes by dragging "wires" out of the inlets / outlets and plug them into another nodes inlets / outlets (inspired from Blenders node based shading and compositing system).
|
||||
You can only connect black with red / red with black. Black is inlet, red is outlet. You can not connect inlet with inlet or outlet with outlet.
|
||||
|
||||
You need Java 1.8 to run the builds.
|
||||
|
||||
|
||||
**Ideas**
|
||||
* Subtitles and image-import for each node
|
||||
* Seperately render UI from workspace
|
||||
* Database
|
||||
* Make workspace dragable / movable (like Google maps)
|
||||
* draw only when necessary (more events) (ditch Processing?)
|
||||
* Test if it runs on windows
|
||||
* Even more testing!
|
||||
|
||||
Pretty sure I'm gonna leave it as is for the time being though.
|
||||
43
build/application.linux-arm64/data/save.csv
Normal file
43
build/application.linux-arm64/data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
build/application.linux-arm64/lib/core.jar
Normal file
BIN
build/application.linux-arm64/lib/core.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.linux-arm64/lib/gluegen-rt.jar
Normal file
BIN
build/application.linux-arm64/lib/gluegen-rt.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.linux-arm64/lib/jogl-all.jar
Normal file
BIN
build/application.linux-arm64/lib/jogl-all.jar
Normal file
Binary file not shown.
BIN
build/application.linux-arm64/lib/ontology.jar
Normal file
BIN
build/application.linux-arm64/lib/ontology.jar
Normal file
Binary file not shown.
5
build/application.linux-arm64/ontology
Executable file
5
build/application.linux-arm64/ontology
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
APPDIR=$(readlink -f "$0")
|
||||
APPDIR=$(dirname "$APPDIR")
|
||||
java -Xms64m -Xmx12000m -Djna.nosys=true -Djava.library.path="$APPDIR:$APPDIR/lib" -cp "$APPDIR:$APPDIR/lib/ontology.jar:$APPDIR/lib/core.jar:$APPDIR/lib/jogl-all.jar:$APPDIR/lib/gluegen-rt.jar:$APPDIR/lib/jogl-all-natives-linux-aarch64.jar:$APPDIR/lib/gluegen-rt-natives-linux-aarch64.jar" ontology "$@"
|
||||
78
build/application.linux-arm64/source/buttons.pde
Normal file
78
build/application.linux-arm64/source/buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
60
build/application.linux-arm64/source/links.pde
Normal file
60
build/application.linux-arm64/source/links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
build/application.linux-arm64/source/nodes.pde
Normal file
129
build/application.linux-arm64/source/nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
577
build/application.linux-arm64/source/ontology.java
Normal file
577
build/application.linux-arm64/source/ontology.java
Normal file
@@ -0,0 +1,577 @@
|
||||
import processing.core.*;
|
||||
import processing.data.*;
|
||||
import processing.event.*;
|
||||
import processing.opengl.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ontology extends PApplet {
|
||||
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
public void setup() {
|
||||
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
public void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
public void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(PApplet.parseInt(random(50, width-50)), PApplet.parseInt(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
public boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = PApplet.parseInt(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
public void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
public void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
public void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
public void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
public boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
public void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3f;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
public void refreshSize() {
|
||||
w = PApplet.parseInt(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
public void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
public void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
public void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(PApplet.parseInt(nodeData[1]), PApplet.parseInt(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, PApplet.parseInt(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
public void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
public void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
public void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void settings() { size(800, 600); }
|
||||
static public void main(String[] passedArgs) {
|
||||
String[] appletArgs = new String[] { "ontology" };
|
||||
if (passedArgs != null) {
|
||||
PApplet.main(concat(appletArgs, passedArgs));
|
||||
} else {
|
||||
PApplet.main(appletArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
build/application.linux-arm64/source/ontology.pde
Normal file
83
build/application.linux-arm64/source/ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
build/application.linux-arm64/source/save_load.pde
Normal file
74
build/application.linux-arm64/source/save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
build/application.linux-arm64/source/ui.pde
Normal file
124
build/application.linux-arm64/source/ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
43
build/application.linux-armv6hf/data/save.csv
Normal file
43
build/application.linux-armv6hf/data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
build/application.linux-armv6hf/lib/core.jar
Normal file
BIN
build/application.linux-armv6hf/lib/core.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.linux-armv6hf/lib/gluegen-rt.jar
Normal file
BIN
build/application.linux-armv6hf/lib/gluegen-rt.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.linux-armv6hf/lib/jogl-all.jar
Normal file
BIN
build/application.linux-armv6hf/lib/jogl-all.jar
Normal file
Binary file not shown.
BIN
build/application.linux-armv6hf/lib/ontology.jar
Normal file
BIN
build/application.linux-armv6hf/lib/ontology.jar
Normal file
Binary file not shown.
5
build/application.linux-armv6hf/ontology
Executable file
5
build/application.linux-armv6hf/ontology
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
APPDIR=$(readlink -f "$0")
|
||||
APPDIR=$(dirname "$APPDIR")
|
||||
java -Djna.nosys=true -Djava.library.path="$APPDIR:$APPDIR/lib" -cp "$APPDIR:$APPDIR/lib/ontology.jar:$APPDIR/lib/core.jar:$APPDIR/lib/jogl-all.jar:$APPDIR/lib/gluegen-rt.jar:$APPDIR/lib/jogl-all-natives-linux-armv6hf.jar:$APPDIR/lib/gluegen-rt-natives-linux-armv6hf.jar" ontology "$@"
|
||||
78
build/application.linux-armv6hf/source/buttons.pde
Normal file
78
build/application.linux-armv6hf/source/buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
60
build/application.linux-armv6hf/source/links.pde
Normal file
60
build/application.linux-armv6hf/source/links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
build/application.linux-armv6hf/source/nodes.pde
Normal file
129
build/application.linux-armv6hf/source/nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
577
build/application.linux-armv6hf/source/ontology.java
Normal file
577
build/application.linux-armv6hf/source/ontology.java
Normal file
@@ -0,0 +1,577 @@
|
||||
import processing.core.*;
|
||||
import processing.data.*;
|
||||
import processing.event.*;
|
||||
import processing.opengl.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ontology extends PApplet {
|
||||
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
public void setup() {
|
||||
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
public void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
public void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(PApplet.parseInt(random(50, width-50)), PApplet.parseInt(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
public boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = PApplet.parseInt(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
public void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
public void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
public void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
public void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
public boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
public void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3f;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
public void refreshSize() {
|
||||
w = PApplet.parseInt(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
public void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
public void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
public void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(PApplet.parseInt(nodeData[1]), PApplet.parseInt(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, PApplet.parseInt(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
public void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
public void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
public void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void settings() { size(800, 600); }
|
||||
static public void main(String[] passedArgs) {
|
||||
String[] appletArgs = new String[] { "ontology" };
|
||||
if (passedArgs != null) {
|
||||
PApplet.main(concat(appletArgs, passedArgs));
|
||||
} else {
|
||||
PApplet.main(appletArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
build/application.linux-armv6hf/source/ontology.pde
Normal file
83
build/application.linux-armv6hf/source/ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
build/application.linux-armv6hf/source/save_load.pde
Normal file
74
build/application.linux-armv6hf/source/save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
build/application.linux-armv6hf/source/ui.pde
Normal file
124
build/application.linux-armv6hf/source/ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
43
build/application.linux32/data/save.csv
Normal file
43
build/application.linux32/data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
build/application.linux32/lib/core.jar
Normal file
BIN
build/application.linux32/lib/core.jar
Normal file
Binary file not shown.
BIN
build/application.linux32/lib/gluegen-rt-natives-linux-i586.jar
Normal file
BIN
build/application.linux32/lib/gluegen-rt-natives-linux-i586.jar
Normal file
Binary file not shown.
BIN
build/application.linux32/lib/gluegen-rt.jar
Normal file
BIN
build/application.linux32/lib/gluegen-rt.jar
Normal file
Binary file not shown.
BIN
build/application.linux32/lib/jogl-all-natives-linux-i586.jar
Normal file
BIN
build/application.linux32/lib/jogl-all-natives-linux-i586.jar
Normal file
Binary file not shown.
BIN
build/application.linux32/lib/jogl-all.jar
Normal file
BIN
build/application.linux32/lib/jogl-all.jar
Normal file
Binary file not shown.
BIN
build/application.linux32/lib/ontology.jar
Normal file
BIN
build/application.linux32/lib/ontology.jar
Normal file
Binary file not shown.
5
build/application.linux32/ontology
Executable file
5
build/application.linux32/ontology
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
APPDIR=$(readlink -f "$0")
|
||||
APPDIR=$(dirname "$APPDIR")
|
||||
java -Xms64m -Xmx12000m -Djna.nosys=true -Djava.library.path="$APPDIR:$APPDIR/lib" -cp "$APPDIR:$APPDIR/lib/ontology.jar:$APPDIR/lib/core.jar:$APPDIR/lib/jogl-all.jar:$APPDIR/lib/gluegen-rt.jar:$APPDIR/lib/jogl-all-natives-linux-i586.jar:$APPDIR/lib/gluegen-rt-natives-linux-i586.jar" ontology "$@"
|
||||
78
build/application.linux32/source/buttons.pde
Normal file
78
build/application.linux32/source/buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
60
build/application.linux32/source/links.pde
Normal file
60
build/application.linux32/source/links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
build/application.linux32/source/nodes.pde
Normal file
129
build/application.linux32/source/nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
577
build/application.linux32/source/ontology.java
Normal file
577
build/application.linux32/source/ontology.java
Normal file
@@ -0,0 +1,577 @@
|
||||
import processing.core.*;
|
||||
import processing.data.*;
|
||||
import processing.event.*;
|
||||
import processing.opengl.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ontology extends PApplet {
|
||||
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
public void setup() {
|
||||
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
public void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
public void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(PApplet.parseInt(random(50, width-50)), PApplet.parseInt(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
public boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = PApplet.parseInt(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
public void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
public void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
public void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
public void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
public boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
public void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3f;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
public void refreshSize() {
|
||||
w = PApplet.parseInt(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
public void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
public void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
public void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(PApplet.parseInt(nodeData[1]), PApplet.parseInt(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, PApplet.parseInt(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
public void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
public void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
public void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void settings() { size(800, 600); }
|
||||
static public void main(String[] passedArgs) {
|
||||
String[] appletArgs = new String[] { "ontology" };
|
||||
if (passedArgs != null) {
|
||||
PApplet.main(concat(appletArgs, passedArgs));
|
||||
} else {
|
||||
PApplet.main(appletArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
build/application.linux32/source/ontology.pde
Normal file
83
build/application.linux32/source/ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
build/application.linux32/source/save_load.pde
Normal file
74
build/application.linux32/source/save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
build/application.linux32/source/ui.pde
Normal file
124
build/application.linux32/source/ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
43
build/application.linux64/data/save.csv
Normal file
43
build/application.linux64/data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
build/application.linux64/lib/core.jar
Normal file
BIN
build/application.linux64/lib/core.jar
Normal file
Binary file not shown.
BIN
build/application.linux64/lib/gluegen-rt-natives-linux-amd64.jar
Normal file
BIN
build/application.linux64/lib/gluegen-rt-natives-linux-amd64.jar
Normal file
Binary file not shown.
BIN
build/application.linux64/lib/gluegen-rt.jar
Normal file
BIN
build/application.linux64/lib/gluegen-rt.jar
Normal file
Binary file not shown.
BIN
build/application.linux64/lib/jogl-all-natives-linux-amd64.jar
Normal file
BIN
build/application.linux64/lib/jogl-all-natives-linux-amd64.jar
Normal file
Binary file not shown.
BIN
build/application.linux64/lib/jogl-all.jar
Normal file
BIN
build/application.linux64/lib/jogl-all.jar
Normal file
Binary file not shown.
BIN
build/application.linux64/lib/ontology.jar
Normal file
BIN
build/application.linux64/lib/ontology.jar
Normal file
Binary file not shown.
5
build/application.linux64/ontology
Executable file
5
build/application.linux64/ontology
Executable file
@@ -0,0 +1,5 @@
|
||||
#!/bin/sh
|
||||
|
||||
APPDIR=$(readlink -f "$0")
|
||||
APPDIR=$(dirname "$APPDIR")
|
||||
java -Xms64m -Xmx12000m -Djna.nosys=true -Djava.library.path="$APPDIR:$APPDIR/lib" -cp "$APPDIR:$APPDIR/lib/ontology.jar:$APPDIR/lib/core.jar:$APPDIR/lib/jogl-all.jar:$APPDIR/lib/gluegen-rt.jar:$APPDIR/lib/jogl-all-natives-linux-amd64.jar:$APPDIR/lib/gluegen-rt-natives-linux-amd64.jar" ontology "$@"
|
||||
78
build/application.linux64/source/buttons.pde
Normal file
78
build/application.linux64/source/buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
60
build/application.linux64/source/links.pde
Normal file
60
build/application.linux64/source/links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
build/application.linux64/source/nodes.pde
Normal file
129
build/application.linux64/source/nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
577
build/application.linux64/source/ontology.java
Normal file
577
build/application.linux64/source/ontology.java
Normal file
@@ -0,0 +1,577 @@
|
||||
import processing.core.*;
|
||||
import processing.data.*;
|
||||
import processing.event.*;
|
||||
import processing.opengl.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ontology extends PApplet {
|
||||
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
public void setup() {
|
||||
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
public void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
public void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(PApplet.parseInt(random(50, width-50)), PApplet.parseInt(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
public boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = PApplet.parseInt(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
public void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
public void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
public void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
public void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
public boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
public void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3f;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
public void refreshSize() {
|
||||
w = PApplet.parseInt(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
public void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
public void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
public void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(PApplet.parseInt(nodeData[1]), PApplet.parseInt(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, PApplet.parseInt(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
public void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
public void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
public void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void settings() { size(800, 600); }
|
||||
static public void main(String[] passedArgs) {
|
||||
String[] appletArgs = new String[] { "ontology" };
|
||||
if (passedArgs != null) {
|
||||
PApplet.main(concat(appletArgs, passedArgs));
|
||||
} else {
|
||||
PApplet.main(appletArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
build/application.linux64/source/ontology.pde
Normal file
83
build/application.linux64/source/ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
build/application.linux64/source/save_load.pde
Normal file
74
build/application.linux64/source/save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
build/application.linux64/source/ui.pde
Normal file
124
build/application.linux64/source/ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
43
build/application.windows32/data/save.csv
Normal file
43
build/application.windows32/data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
build/application.windows32/lib/core.jar
Normal file
BIN
build/application.windows32/lib/core.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.windows32/lib/gluegen-rt.jar
Normal file
BIN
build/application.windows32/lib/gluegen-rt.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.windows32/lib/jogl-all.jar
Normal file
BIN
build/application.windows32/lib/jogl-all.jar
Normal file
Binary file not shown.
BIN
build/application.windows32/lib/ontology.jar
Normal file
BIN
build/application.windows32/lib/ontology.jar
Normal file
Binary file not shown.
BIN
build/application.windows32/ontology.exe
Executable file
BIN
build/application.windows32/ontology.exe
Executable file
Binary file not shown.
78
build/application.windows32/source/buttons.pde
Normal file
78
build/application.windows32/source/buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
60
build/application.windows32/source/links.pde
Normal file
60
build/application.windows32/source/links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
build/application.windows32/source/nodes.pde
Normal file
129
build/application.windows32/source/nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
577
build/application.windows32/source/ontology.java
Normal file
577
build/application.windows32/source/ontology.java
Normal file
@@ -0,0 +1,577 @@
|
||||
import processing.core.*;
|
||||
import processing.data.*;
|
||||
import processing.event.*;
|
||||
import processing.opengl.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ontology extends PApplet {
|
||||
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
public void setup() {
|
||||
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
public void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
public void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(PApplet.parseInt(random(50, width-50)), PApplet.parseInt(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
public boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = PApplet.parseInt(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
public void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
public void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
public void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
public void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
public boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
public void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3f;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
public void refreshSize() {
|
||||
w = PApplet.parseInt(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
public void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
public void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
public void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(PApplet.parseInt(nodeData[1]), PApplet.parseInt(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, PApplet.parseInt(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
public void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
public void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
public void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void settings() { size(800, 600); }
|
||||
static public void main(String[] passedArgs) {
|
||||
String[] appletArgs = new String[] { "ontology" };
|
||||
if (passedArgs != null) {
|
||||
PApplet.main(concat(appletArgs, passedArgs));
|
||||
} else {
|
||||
PApplet.main(appletArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
build/application.windows32/source/ontology.pde
Normal file
83
build/application.windows32/source/ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
build/application.windows32/source/save_load.pde
Normal file
74
build/application.windows32/source/save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
build/application.windows32/source/ui.pde
Normal file
124
build/application.windows32/source/ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
43
build/application.windows64/data/save.csv
Normal file
43
build/application.windows64/data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
build/application.windows64/lib/core.jar
Normal file
BIN
build/application.windows64/lib/core.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.windows64/lib/gluegen-rt.jar
Normal file
BIN
build/application.windows64/lib/gluegen-rt.jar
Normal file
Binary file not shown.
Binary file not shown.
BIN
build/application.windows64/lib/jogl-all.jar
Normal file
BIN
build/application.windows64/lib/jogl-all.jar
Normal file
Binary file not shown.
BIN
build/application.windows64/lib/ontology.jar
Normal file
BIN
build/application.windows64/lib/ontology.jar
Normal file
Binary file not shown.
BIN
build/application.windows64/ontology.exe
Executable file
BIN
build/application.windows64/ontology.exe
Executable file
Binary file not shown.
78
build/application.windows64/source/buttons.pde
Normal file
78
build/application.windows64/source/buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
60
build/application.windows64/source/links.pde
Normal file
60
build/application.windows64/source/links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
build/application.windows64/source/nodes.pde
Normal file
129
build/application.windows64/source/nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
577
build/application.windows64/source/ontology.java
Normal file
577
build/application.windows64/source/ontology.java
Normal file
@@ -0,0 +1,577 @@
|
||||
import processing.core.*;
|
||||
import processing.data.*;
|
||||
import processing.event.*;
|
||||
import processing.opengl.*;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.ArrayList;
|
||||
import java.io.File;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ontology extends PApplet {
|
||||
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
public void setup() {
|
||||
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
public void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
public void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
public void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(PApplet.parseInt(random(50, width-50)), PApplet.parseInt(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
public boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
public void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = PApplet.parseInt(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
public void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
public void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
public void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
public void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
public void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
public void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
public boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
public void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3f;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3f;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
public void refreshSize() {
|
||||
w = PApplet.parseInt(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
public void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
public void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
public void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
public void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(PApplet.parseInt(nodeData[1]), PApplet.parseInt(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, PApplet.parseInt(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
public void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
public void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
public void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
public void settings() { size(800, 600); }
|
||||
static public void main(String[] passedArgs) {
|
||||
String[] appletArgs = new String[] { "ontology" };
|
||||
if (passedArgs != null) {
|
||||
PApplet.main(concat(appletArgs, passedArgs));
|
||||
} else {
|
||||
PApplet.main(appletArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
83
build/application.windows64/source/ontology.pde
Normal file
83
build/application.windows64/source/ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
build/application.windows64/source/save_load.pde
Normal file
74
build/application.windows64/source/save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
build/application.windows64/source/ui.pde
Normal file
124
build/application.windows64/source/ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
78
buttons.pde
Normal file
78
buttons.pde
Normal file
@@ -0,0 +1,78 @@
|
||||
int buttonCount = 6;
|
||||
int i_buttonId;
|
||||
|
||||
void initButtons() {
|
||||
buttons[0] = new Button(10, 10, "Add Node");
|
||||
buttons[1] = new Button(104, 10, "Delete Node");
|
||||
buttons[2] = new Button(10, 50, "Dark/Bright Mode");
|
||||
buttons[3] = new Button(10, 90, "Save");
|
||||
buttons[4] = new Button(10, 130, "Open");
|
||||
buttons[5] = new Button(10, 170, "Export Image");
|
||||
/* buttons[0] = new Button(10, 10, "Node Hinzufügen");
|
||||
buttons[1] = new Button(155, 10, "Löschen");
|
||||
buttons[2] = new Button(10, 50, "Farben umkehren");
|
||||
buttons[3] = new Button(10, 90, "Speichern");
|
||||
buttons[4] = new Button(10, 130, "Öffnen");
|
||||
buttons[5] = new Button(10, 170, "Bild Exportieren");*/
|
||||
}
|
||||
|
||||
void buttonFunctions(int functionID) {
|
||||
switch (functionID) {
|
||||
case(0):
|
||||
addNode(int(random(50, width-50)), int(random(30, height-150)), "");
|
||||
i_selectedNode = nodeCount-1;
|
||||
break;
|
||||
case(1):
|
||||
deleteSelectedNode();
|
||||
break;
|
||||
case(2):
|
||||
darkMode = !darkMode;
|
||||
break;
|
||||
case(3):
|
||||
saveCSV(dataPath("save.csv"));
|
||||
selectOutput("Where to save .csv file to?", "saveCSVFile");
|
||||
break;
|
||||
case(4):
|
||||
selectInput("Select csv File", "loadCSVFile");
|
||||
break;
|
||||
case(5):
|
||||
selectOutput("Where to export .png image file to?", "savePNGFile");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Button buttons[] = new Button[buttonCount];
|
||||
|
||||
class Button {
|
||||
int id, x, y, w, h;
|
||||
String label;
|
||||
|
||||
boolean hover() {
|
||||
return (mouseX > x && mouseX < x+w && mouseY > y && mouseY < y+h) ? true : false;
|
||||
}
|
||||
|
||||
void click() {
|
||||
buttonFunctions(id);
|
||||
}
|
||||
Button(int x_, int y_, String label_) {
|
||||
id = i_buttonId;
|
||||
i_buttonId++;
|
||||
x = x_;
|
||||
y = y_ ;
|
||||
label = label_;
|
||||
w = int(textWidth(label))+18;
|
||||
h = 32;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(0);
|
||||
strokeWeight(1);
|
||||
fill(255, 127);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(0);
|
||||
text(label, x+9, y+h/2+5);
|
||||
}
|
||||
}
|
||||
43
data/save.csv
Normal file
43
data/save.csv
Normal file
@@ -0,0 +1,43 @@
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Biological Process,395,537,32,33
|
||||
Physiological Process,292,455,34
|
||||
Cellular Process,483,455,34
|
||||
Cellular Physiological Process,391,375,36,35
|
||||
Cell Cycle,305,296,40,41
|
||||
Cell Division,544,265,37
|
||||
Cytokinesis,543,165,38
|
||||
Cytokinesis after Meiosis,399,54
|
||||
M Phase of Meiotic Cell Cycle,310,144,38
|
||||
M Phase,239,225,39
|
||||
Meiotic Cell Cycle,392,225,39
|
||||
|
||||
|
Can't render this file because it has a wrong number of fields in line 33.
|
BIN
examples/example_bright.png
Normal file
BIN
examples/example_bright.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 28 KiB |
BIN
examples/gui_dark.png
Normal file
BIN
examples/gui_dark.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 114 KiB |
60
links.pde
Normal file
60
links.pde
Normal file
@@ -0,0 +1,60 @@
|
||||
int linkCount;
|
||||
|
||||
boolean dragLink; //state of dragging a link
|
||||
int dragOriginLet = 0; //dragging from inlet: -1. dragging from outlet: 1.
|
||||
int dragOriginId = -1; //which nodes out- / inlet did user click on?
|
||||
|
||||
void Link(int parentNode, int targetNode) {
|
||||
/**
|
||||
* Check if user is adding or removing a link
|
||||
*/
|
||||
int exists = -1;
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].parentNode == parentNode && links[i].targetNode == targetNode) {
|
||||
exists = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (exists != -1) {
|
||||
/**
|
||||
* !active state is pretty much the same as deleted state that the node-class comes with
|
||||
*/
|
||||
links[exists].active = !links[exists].active;
|
||||
} else {
|
||||
links[linkCount] = new Link(parentNode, targetNode);
|
||||
linkCount++;
|
||||
}
|
||||
}
|
||||
|
||||
class Link {
|
||||
int parentNode, targetNode;
|
||||
boolean active;
|
||||
PVector link = new PVector(0, 0);
|
||||
|
||||
Link(int parentNode_, int targetNode_) {
|
||||
parentNode = parentNode_;
|
||||
targetNode = targetNode_;
|
||||
active = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This could be an event that only gets called when nodes are moved or resized.
|
||||
*/
|
||||
void update() {
|
||||
link.x = nodes[targetNode].inletCenter.x - nodes[parentNode].outletCenter.x;
|
||||
link.y = nodes[targetNode].inletCenter.y - nodes[parentNode].outletCenter.y;
|
||||
}
|
||||
|
||||
void display() {
|
||||
stroke(darkMode? 255 : 0);
|
||||
strokeWeight(2);
|
||||
pushMatrix();
|
||||
translate(nodes[parentNode].outletCenter.x, nodes[parentNode].outletCenter.y);
|
||||
line(0, 0, link.x, link.y);
|
||||
translate(-nodes[parentNode].outletCenter.x+(nodes[parentNode].outletCenter.x+nodes[targetNode].inletCenter.x)/2, -nodes[parentNode].outletCenter.y+(nodes[parentNode].outletCenter.y+nodes[targetNode].inletCenter.y)/2);
|
||||
rotate(link.heading());
|
||||
fill(darkMode? 0 : 255);
|
||||
triangle(0, textSize/2, textSize, 0, 0, -textSize/2);
|
||||
popMatrix();
|
||||
}
|
||||
}
|
||||
129
nodes.pde
Normal file
129
nodes.pde
Normal file
@@ -0,0 +1,129 @@
|
||||
int nodeCount;
|
||||
int i_selectedNode = -1;
|
||||
int padding = textSize/3*2; //Padding between text and surrounding box
|
||||
int letTolerance = 10; //Widens the clickable areas of in/outlets a bit
|
||||
|
||||
void addNode(int x, int y, String title) {
|
||||
nodes[nodeCount] = new Node(x, y, title);
|
||||
nodeCount++;
|
||||
}
|
||||
|
||||
void deselect() {
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
|
||||
void deleteSelectedNode() { //Seperate from class for garbage collector reasons
|
||||
if (i_selectedNode != -1) {
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].targetNode == i_selectedNode || links[i].parentNode == i_selectedNode) {
|
||||
links[i].active = false;
|
||||
}
|
||||
}
|
||||
nodes[i_selectedNode].deleted = true;
|
||||
i_selectedNode = -1;
|
||||
}
|
||||
}
|
||||
|
||||
class Node {
|
||||
String title;
|
||||
int id;
|
||||
int inlets = 2;
|
||||
int outlets = 2;
|
||||
int x, y;
|
||||
int h = textSize+2*padding;
|
||||
int w = textSize+2*padding;
|
||||
PVector dragMouseStartPoint = new PVector(0, 0);
|
||||
PVector outletCenter = new PVector(0, 0);
|
||||
PVector inletCenter = new PVector(0, 0);
|
||||
boolean deleted;
|
||||
boolean drag;
|
||||
boolean hover() {
|
||||
if (mouseX > x-w/2 && mouseX < x+w/2 && mouseY > y-h/2 && mouseY < y+h/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverOutlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y-padding-textSize/2-(textSize+padding)/2-letTolerance && mouseY < y-padding-textSize/2) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
boolean hoverInlet() {
|
||||
if (mouseX > x-(textSize+padding)/2-letTolerance && mouseX < x+(textSize+padding)/2+letTolerance && mouseY > y+padding+textSize/2 && mouseY < y+padding+textSize/2+(textSize+padding)/2+letTolerance) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Node(int x_, int y_, String title_) {
|
||||
id = nodeCount;
|
||||
title = title_;
|
||||
x = x_;
|
||||
y = y_;
|
||||
setVectors();
|
||||
refreshSize();
|
||||
}
|
||||
|
||||
void setVectors() {
|
||||
outletCenter.x = x;
|
||||
outletCenter.y = y-(padding+textSize/2)*1.3;
|
||||
inletCenter.x = x;
|
||||
inletCenter.y = y+(padding+textSize/2)*1.3;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when changing nodes title or when zooming via mouse-wheel
|
||||
*/
|
||||
void refreshSize() {
|
||||
w = int(textWidth(title))+2*padding;
|
||||
h = textSize+2*padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update-function is really only necessary when dragging the node
|
||||
*/
|
||||
void update() {
|
||||
if (drag) {
|
||||
x -= dragMouseStartPoint.x - mouseX;
|
||||
dragMouseStartPoint.x = mouseX;
|
||||
y -= dragMouseStartPoint.y - mouseY;
|
||||
dragMouseStartPoint.y = mouseY;
|
||||
setVectors();
|
||||
}
|
||||
}
|
||||
|
||||
void display() {
|
||||
/**
|
||||
* Selected nodes border
|
||||
*/
|
||||
if (i_selectedNode == id) {
|
||||
noStroke();
|
||||
fill(150, 100);
|
||||
rect(x, y, w+20, h+20, 4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inlet & Outlet
|
||||
*/
|
||||
stroke(255, darkMode? 255 : 0);
|
||||
strokeWeight(1);
|
||||
fill(255, 0, 0);
|
||||
ellipse(x, y-padding-textSize/2, textSize+padding, textSize+padding);
|
||||
fill(0);
|
||||
ellipse(x, y+padding+textSize/2, textSize+padding, textSize+padding);
|
||||
|
||||
/**
|
||||
* Box & Title
|
||||
*/
|
||||
stroke(127);
|
||||
strokeWeight(2);
|
||||
fill(50);
|
||||
rect(x, y, w, h, 4);
|
||||
fill(255);
|
||||
text(title, x, y+textSize/3);
|
||||
}
|
||||
}
|
||||
83
ontology.pde
Normal file
83
ontology.pde
Normal file
@@ -0,0 +1,83 @@
|
||||
Node nodes[] = new Node[1000];
|
||||
Link links[] = new Link[6000];
|
||||
|
||||
int textSize = 14;
|
||||
boolean darkMode = true;
|
||||
|
||||
void setup() {
|
||||
size(800, 600);
|
||||
surface.setResizable(true);
|
||||
|
||||
textSize(textSize);
|
||||
|
||||
initButtons();
|
||||
|
||||
/**
|
||||
* When saving, a copy of the save-file is stored locally which is opened when starting the program
|
||||
*/
|
||||
try {
|
||||
loadCSV(dataPath("save.csv"));
|
||||
}
|
||||
catch(Exception e) {
|
||||
println("No File found, starting blank");
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
background(darkMode? 0 : 255);
|
||||
|
||||
/**
|
||||
* Update and display links
|
||||
*/
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
if (links[i].active) {
|
||||
links[i].update();
|
||||
links[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display nodes
|
||||
*/
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
nodes[i].update();
|
||||
nodes[i].display();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update and display ui, hide via exporting-flag for easy image-saving
|
||||
* Not all buttons always show, that's why this isn't in a loop
|
||||
*/
|
||||
if (!exporting) {
|
||||
textSize(14);
|
||||
rectMode(CORNER);
|
||||
textAlign(CORNER);
|
||||
buttons[0].display();
|
||||
if (i_selectedNode != -1) buttons[1].display();
|
||||
buttons[2].display();
|
||||
buttons[3].display();
|
||||
buttons[4].display();
|
||||
buttons[5].display();
|
||||
rectMode(CENTER);
|
||||
textAlign(CENTER);
|
||||
textSize(textSize);
|
||||
} else {
|
||||
save(savePNGpath);
|
||||
exporting = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pull "wire" out of in/outlet before creating a link (see mouseReleased in ui)
|
||||
*/
|
||||
if (dragLink) {
|
||||
stroke(darkMode? 255:0);
|
||||
strokeWeight(2);
|
||||
if (dragOriginLet == -1) {
|
||||
line(nodes[dragOriginId].inletCenter.x, nodes[dragOriginId].inletCenter.y, mouseX, mouseY);
|
||||
} else if (dragOriginLet == 1) {
|
||||
line(nodes[dragOriginId].outletCenter.x, nodes[dragOriginId].outletCenter.y, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
74
save_load.pde
Normal file
74
save_load.pde
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* Saving and loading is a messy hack!
|
||||
* You'll get a blank line in your save file for each deleted object.
|
||||
* That's because of my lack of skills of dodging the garbage collector.
|
||||
* I didn't loose data to corruption yet.
|
||||
* Don't touch the save files if you don't want to mess them up!
|
||||
**/
|
||||
|
||||
boolean exporting;
|
||||
String savePNGpath = dataPath("save.png");
|
||||
|
||||
void savePNGFile(File selection) {
|
||||
savePNGpath = selection.getPath();
|
||||
exporting = true;
|
||||
}
|
||||
|
||||
void saveCSVFile(File selection) {
|
||||
saveCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSVFile(File selection) {
|
||||
loadCSV(selection.getPath());
|
||||
}
|
||||
|
||||
void loadCSV(String path) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
//nodes[i].deleted = true;
|
||||
i_selectedNode = i;
|
||||
deleteSelectedNode();
|
||||
}
|
||||
nodeCount = 0;
|
||||
|
||||
for (int i = 0; i < linkCount; i++) {
|
||||
links[i].active = false;
|
||||
}
|
||||
linkCount = 0;
|
||||
|
||||
String[] loadString = loadStrings(path);
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
//This is ultra shitty
|
||||
if (loadString[i].length() == 0) {
|
||||
addNode(-1000, -1000, " ");
|
||||
i_selectedNode = nodeCount - 1;
|
||||
deleteSelectedNode();
|
||||
//nodes[nodeCount-1].deleted = true;
|
||||
} else {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
addNode(int(nodeData[1]), int(nodeData[2]), nodeData[0]);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < loadString.length-1; i++) {
|
||||
String nodeData[] = split(loadString[i], ',');
|
||||
for (int j = 3; j < nodeData.length; j++) {
|
||||
Link(i, int(nodeData[j]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void saveCSV(String path) {
|
||||
String saveString = "";
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
if (!nodes[i].deleted) {
|
||||
saveString += nodes[i].title + "," + nodes[i].x + "," + nodes[i].y;
|
||||
for (int j = 0; j < linkCount; j++) {
|
||||
if (links[j].parentNode == i && links[j].active) {
|
||||
saveString += "," + str(links[j].targetNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
saveString += "\n";
|
||||
}
|
||||
String[] saveArray = split(saveString, '\n');
|
||||
saveStrings(path, saveArray);
|
||||
}
|
||||
124
ui.pde
Normal file
124
ui.pde
Normal file
@@ -0,0 +1,124 @@
|
||||
/**
|
||||
* Keys only get caught for changing a nodes title.
|
||||
* Previous title is remembered in savedTitle and restored when hitting Escape
|
||||
*/
|
||||
String savedTitle;
|
||||
void keyPressed() {
|
||||
if (key == ESC) {
|
||||
key = 0;
|
||||
}
|
||||
if (i_selectedNode != -1) {
|
||||
if (keyCode == BACKSPACE) {
|
||||
if (nodes[i_selectedNode].title.length() > 0) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title.substring(0, nodes[i_selectedNode].title.length()-1);
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
} else if (keyCode == DELETE) {
|
||||
deleteSelectedNode();
|
||||
} else if (keyCode == ESC) {
|
||||
nodes[i_selectedNode].title = savedTitle;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
deselect();
|
||||
} else if (keyCode == RETURN || keyCode == ENTER) {
|
||||
deselect();
|
||||
} else if (keyCode != SHIFT && keyCode != RETURN && keyCode != ENTER && keyCode != CONTROL) {
|
||||
nodes[i_selectedNode].title = nodes[i_selectedNode].title + key;
|
||||
nodes[i_selectedNode].refreshSize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void mousePressed() {
|
||||
if (mouseButton == LEFT) {
|
||||
/**
|
||||
* Either press a button...
|
||||
*/
|
||||
boolean buttonClicked = false;
|
||||
for (int i = 0; i < buttons.length; i++) {
|
||||
if (buttons[i].hover()) {
|
||||
buttons[i].click();
|
||||
//Not able to break out of here without using a flag
|
||||
buttonClicked = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!buttonClicked) {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
/**
|
||||
* ...or select / drag a node...
|
||||
*/
|
||||
if (nodes[i].hover()) {
|
||||
i_selectedNode = i;
|
||||
savedTitle = nodes[i].title;
|
||||
nodes[i].drag = true;
|
||||
nodes[i].dragMouseStartPoint.x = mouseX;
|
||||
nodes[i].dragMouseStartPoint.y = mouseY;
|
||||
break;
|
||||
}
|
||||
/**
|
||||
* ...or pull a new link out of an inlet or outlet.
|
||||
*/
|
||||
else if (nodes[i].hoverInlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = -1;
|
||||
dragOriginId = i;
|
||||
} else if (nodes[i].hoverOutlet()) {
|
||||
dragLink = true;
|
||||
dragOriginLet = 1;
|
||||
dragOriginId = i;
|
||||
}
|
||||
|
||||
//deselecting the shit out of this for reasons I don't remember, no care to improve right now
|
||||
deselect();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create links
|
||||
*/
|
||||
void mouseReleased() {
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].drag = false;
|
||||
if (dragLink && dragOriginId != i) {
|
||||
if (nodes[i].hoverInlet() && dragOriginLet == 1) {
|
||||
|
||||
Link(dragOriginId, i);
|
||||
}
|
||||
if (nodes[i].hoverOutlet() && dragOriginLet == -1) {
|
||||
|
||||
Link(i, dragOriginId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset drag&drop states
|
||||
*/
|
||||
dragLink = false;
|
||||
dragOriginLet = 0;
|
||||
dragOriginId = -1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Scaling is tied to textSize. Having the UI on a seperate PGraphics would be better, but it's good enough for now
|
||||
*/
|
||||
int zoomDelta = 3;
|
||||
void mouseWheel(MouseEvent event) {
|
||||
float zoom = event.getAmount();
|
||||
if (zoom < 0) {
|
||||
textSize += zoomDelta;
|
||||
} else if (zoom > 0) {
|
||||
if (textSize - zoomDelta > 0) {
|
||||
textSize -= zoomDelta;
|
||||
}
|
||||
}
|
||||
padding = textSize/3*2;
|
||||
for (int i = 0; i < nodeCount; i++) {
|
||||
nodes[i].refreshSize();
|
||||
nodes[i].setVectors();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user