Example
This examples comes with a Menu.
Needs a folder Polys in the Sketch Folder.
You might want to DISTRIBUTE he code over several tabs as indicated.
(it has been copied together (Concatenated) from multiple tabs automatically)
Example for file content
610.0,259.0
822.0,363.0
786.0,465.0
461.0,615.0
301.0,581.0
only ONE polygon
// ********************************************************************************
// joined pde-file of folder polygonEditor1
// ********************************************************************************
// ********************************************************************************
// tab: polygonEditor1.pde main file (file name is folder name)
//https://discourse.processing.org/t/multiple-polygons-loaded-user-selects-polygon-of-interest-user-edits-selected-polygon-nodes-user-saves-polygon/41774
// constants ---
// states for the program (constants)
final int SPLASH_SCREEN = 0;
final int MENU = 1;
final int EDITOR = 2;
final int HELP = 3;
final int SAVE = 4;
final int LOAD = 5;
final int AddPoints = 6;
int stateProgram = SPLASH_SCREEN; // current state
final color BLACK = color(0);
final color WHITE = color(255);
final color RED = color(255, 0, 0);
final color GREEN = color(0, 255, 0);
final color BLUE = color(0, 0, 255);
final color PINK = color(255, 0, 255);
final color YELLOW = color(255, 255, 0);
final color TURQUOISE = color(0, 255, 255);
final color YELLOW2 = (#FFF80A);
final color BROWN = #B9780D;
// -------------------------------------------------------------------------------
// Variables and objects
ArrayList<PVector> polygon = new ArrayList();
// Toolbox save / load
ClassSaveLoadTools classSaveLoadTools;
// Menu
Menu mainMenu;
String helpText1= "Polygon Editor\nEsc goes back to Menu normally";
boolean showHelp = true;
float burgerx1= 20;
float burgery1= 20;
// dragging points
boolean mouseDrag = false;
int selectedPoint;
// -------------------------------------------------------------------------------------
void settings() {
size( 1200, 900 );
}
void setup() {
surface.setTitle("Polygon Editor");
//font
PFont pf = createFont("ARIAL", 14);
textFont(pf);
// load
classSaveLoadTools = new ClassSaveLoadTools();
// Main Menu
mainMenu = new Menu();
} // setup
void draw() {
switch(stateProgram) {
case SPLASH_SCREEN:
drawForStateSplashScreen();
break;
case EDITOR:
drawForStateEditor();
break;
case HELP:
drawForStateHelp();
break;
case SAVE:
// wait for Save Dialog
classSaveLoadTools.waitForSaveDialog();
break;
case LOAD:
// wait for Load Dialog
classSaveLoadTools.waitForLoadDialog();
break;
case MENU:
showMenu();
break;
case AddPoints:
drawForStateAddPoints();
break;
default:
stateProgram = EDITOR; // ERROR - RESET
break;
} //switch
//
} // draw
//
// ********************************************************************************
// tab: cMenu.pde
// this is the Main Menu on the center
class Menu {
final int x1 = int(width/2.0-100);
final int y1 = 210;
final color bkColor = color(133);
boolean open=true;
final String[] textsForMenu = {
"Add points",
"Editor ",
"Load ",
"Save ",
"Help Screen",
"Delete All"
};
// number of buttons in Pane
int upperBound=textsForMenu.length;
Button[] myButtons=new Button[upperBound]; // make a button of type class Button
// constr
Menu() {
// make buttons
for (int i=0; i < upperBound; i++) {
// xi, yi, wi, hi, seli, visible, text from elementsForMenu, id from i
myButtons[i] = new Button(x1+10, (y1+30) + i * 75,
330, 50,
false, true,
textsForMenu[i],
i);
}
}// constr
void display() {
strokeWeight(1);
textSize(14);
fill(255);
textAlign(LEFT, TOP);
textSize(24);
for (Button btn : myButtons) {
btn.draw();
}//for
}//method
int myMousePressed() {
boolean returnValue=false;
int result = -1;
for (Button btn : myButtons) {
if (btn.myMousePressed()) {
result = btn.id;
returnValue = true;
}//if
}//for
if (returnValue) {
for (Button btn : myButtons) {
btn.selected=false;
}
}
return result;
}//method
//
} // class
//
// ********************************************************************************
// tab: cMenuButton.pde
class Button {
// only used for Pane
int x, y,
w, h,
id;
boolean selected, vis;
String text;
Button(int x, int y,
int w, int h,
boolean sel, boolean vis,
String atext,
int id) {
//
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.selected = sel;
this.vis = vis;
this.text = atext;
this.id = id;
}
void draw() {
if ( this.vis ) {
strokeWeight(1);
if (this.selected) fill(0, 200, 0);
else fill(0, 0, 200);
if (this.over()) stroke(200, 0, 200);
else stroke(0, 200, 200);
rect(this.x, this.y,
this.w, this.h);
noStroke();
fill(200);
textAlign(LEFT, TOP);
text(text,
x + 4, y + 3,
w-10, 900);
}
}
boolean over() {
return
mouseX > this.x &
mouseX < this.x + this.w &
mouseY > this.y &
mouseY < this.y + this.h;
}
boolean myMousePressed() {
//called from main mousePressed
return
over();
}
//
} // class
//
// ********************************************************************************
// tab: cSaveLoad.pde
// Save and load
// the two 'callback' functions MUST BE OUTSIDE THE CLASS
// 3 blocks with 2 functions each, for save and load
class ClassSaveLoadTools {
// editor path and file extension
final String pathFolder = "Polys";
final String defaultFile = "list1.txt";
final String fileExtension = ".txt";
// Paths (returned by 'callback' functions after using save and load)
String savePath="";
String loadPath="";
// --------------------------------------------------------------------
// constr
ClassSaveLoadTools() {
loadPath = sketchPath("") +
"//"
+pathFolder
+"//"
+defaultFile;
println("Loaded: "
+loadPath);
} // constr
// --------------------------------------------------------------------
// the two init functions
void initSave() {
// init save process
// reset
savePath="";
// make date time stamp (the expression nf(n,2) means leading zero: 2 becomes 02)
String dateTimeStamp = year()
+ nf(month(), 2)
+ nf(day(), 2)
+ "-"
+ nf(hour(), 2)
+ nf(minute(), 2)
+ nf(second(), 2);
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()
+ "//"
+ pathFolder
+ "//"
+ dateTimeStamp
+ fileExtension);
// open the dialog
selectOutput("Select a file to write to", "fileSelectedSave", fileDescription);
// set state to wait
stateProgram=SAVE;
}
void initLoad() {
// init load process
// reset
loadPath="";
// prepare fileDescription which occurs in the dialogue
File fileDescription = new File( sketchPath()+"//"+pathFolder+"//"+"*" + fileExtension );
// open the dialog
selectInput("Select a file to load", "fileSelectedLoad", fileDescription);
// set state to wait
stateProgram=LOAD;
}
// ----------------------------------------------------
// waiting
void waitForSaveDialog() {
if (!savePath.equals("")) {
// waiting is over
saveIt();
// go back
stateProgram=EDITOR;
}
}
void waitForLoadDialog() {
if (!loadPath.equals("")) {
// waiting is over
loadIt();
// go back
stateProgram=EDITOR;
}
}
// ----------------------------------------------------
// executing save and load [AFTER the dialogs]
void saveIt() {
// save
// get the data from the ArrayList
String[] sArray = new String[0];
for (PVector pv : polygon ) {
sArray = (String[]) append ( sArray, pv.x+","+pv.y );
}
// check if file extension (fileExtension, e.g. .txt) is there
int len = savePath.length();
if (len<4 || !savePath.substring( len-4 ).equals(fileExtension)) {
// file Extension is not present, we have to add it
savePath += fileExtension; // add the file Extension
}
// save
println("Saved: " + savePath);
saveStrings (savePath, sArray);
}
void loadIt() {
String[] linesInFile = loadStrings(loadPath);
println("loading "
+ linesInFile.length
+ " lines.");
for (int i=0; i<linesInFile.length; i++) {
if (linesInFile[i].trim().equals(""))
continue;
if (linesInFile[i].trim().substring(0, 2).equals("//")) {
print("Skipped line (which is commented out with //) #"+i+": ");
println(linesInFile[i]);
continue;
}
String[] elementsInLine = split(linesInFile[i], ",");
if (elementsInLine.length<2) {
print("Error in line #"+i+": ");
println(linesInFile[i]);
continue;
}
PVector newPv = new PVector ( int( elementsInLine[0]), int(elementsInLine[1]));
polygon.add(newPv);
}//for
}
//
}//class
//
// ********************************************************************************
// tab: InputsKeyb.pde
void keyPressed() {
switch(stateProgram) {
case SPLASH_SCREEN:
stateProgram = MENU; // leave state
key=0; // kill ESC
break;
case MENU:
// just in case the user has no mouse
if (key==' ') {
stateProgram=EDITOR; // leave state
} else if (key==ENTER||key==RETURN) {
//
} else if (key=='0'||key=='1'||key=='2') {
//
}
key=0; // kill ESC
break;
case HELP:
key=0; // kill ESC
stateProgram=MENU; // leave state
break;
case EDITOR:
if (key==DELETE&&mouseDrag&&selectedPoint!=-1) {
polygon.remove(selectedPoint);
mouseDrag=false;
selectedPoint=-1;
} else if (key==ESC) {
key=0; // kill ESC
stateProgram=MENU; // leave state
}
break;
case AddPoints:
if (key==ESC) {
key=0; // kill ESC
stateProgram=MENU; // leave state
}
break;
default:
stateProgram=SPLASH_SCREEN;
break;
}//switch
}
// ********************************************************************************
// tab: InputsMouse.pde
void mousePressed() {
switch(stateProgram) {
case SPLASH_SCREEN:
stateProgram=MENU; // leave state
key=0; // kill ESC
break;
case HELP:
stateProgram = MENU;
key=0; // kill ESC
break;
case EDITOR:
mousePressedForStateEDITOR();
break;
case MENU:
mousePressedForStateMENU();
break;
case AddPoints:
polygon.add(new PVector(mouseX, mouseY));
break;
default:
println("Error 129");
exit();
break;
}//switch
}
void mouseReleased() {
mouseDrag=false;
}//func
// ---------------------------------------------------------------------------------------------
void mousePressedForStateMENU() {
// Eval buttons of Menu.
// Numbers in switch() must match the order in class Menu.
int result = mainMenu.myMousePressed();
switch(result) {
case -1:
// ignore
break;
case 0:
stateProgram=AddPoints;
break;
case 1:
// Editor
stateProgram = EDITOR;
break;
case 2:
// load
classSaveLoadTools.initLoad();
break;
case 3:
// SAVE dialog
classSaveLoadTools.initSave();
break;
case 4:
stateProgram=HELP;
break;
case 5:
// delete all
polygon.clear();
break;
default:
println("Error 836 with "
+result
+" ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
exit();
break;
}//switch
}//func
void mousePressedForStateEDITOR() {
// mouse inputs
if (mouseButton == RIGHT ) {
// ....
return;
}
if (mouseButton == CENTER) {
// ....
return;
}
// ---
// technically not necessary
if (mouseButton != LEFT ) {
return;
}
// ---
// LEFT mouse button
if (dist(mouseX, mouseY, burgerx1, burgery1) < 44) {
stateProgram=MENU;
return;
}
// are we already dragging?
if (mouseDrag) {
return; // leave
}
// search point to start dragging
for (int i=0; i<polygon.size(); i++) {
strokeWeight(10);
fill(255);
float x = polygon.get(i).x;
float y = polygon.get(i).y;
if (dist(mouseX, mouseY, x, y) < 22) {
selectedPoint = i;
mouseDrag=true;
return;
}
}
//
}//func
//
// ********************************************************************************
// tab: StateAdd.pde
void drawForStateAddPoints() {
background(0);
// title
int xpos= width/2;
int ypos=32;
textSize(29);
fill(WHITE);
textAlign(CENTER);
text("Add points",
xpos, ypos);
textSize(14);
textSize(14);
noFill();
for (int i=0; i<polygon.size(); i++) {
strokeWeight(10);
float x = polygon.get(i).x;
float y = polygon.get(i).y;
fill(255);
point(x, y);
ellipse(x, y, 4, 4);
fill(2550, 0, 0);
textSize(24);
text(i, x+10, y);
}
}
// ********************************************************************************
// tab: StateEditor.pde
// for state Editor
void drawForStateEditor() {
// draw For State "Editor"
background(0);
showStatusBar("Burger Symbol for Menu");
textSize(14);
noFill();
for (int i=0; i<polygon.size(); i++) {
strokeWeight(10);
fill(255);
float x = polygon.get(i).x;
float y = polygon.get(i).y;
point(x, y);
ellipse(x, y, 4, 4);
fill(2550, 0, 0);
textSize(24);
text(i, x+10, y);
}
if (mouseDrag) {
polygon.get(selectedPoint).x=mouseX;
polygon.get(selectedPoint).y=mouseY;
}
fill(WHITE);
//-------------------
// title
int xpos= width/2;
int ypos=32;
textSize(29);
fill(WHITE);
textAlign(CENTER);
text("Editor ",
xpos, ypos);
textSize(14);
text("Drag Points (drag and press delete key to delete the point)",
xpos, ypos+33);
textAlign(LEFT);
// burger menu
burgerMenuSign();
// Message
fill(WHITE);
text ("Number of Points:\n"
+polygon.size(),
width-141, height-210);
// small help text, top left
if (showHelp) {
fill(255);
text(helpText1,
22, 100,
310, 900);
} else {
fill(255);
text("x",
22, 100,
310, 900);
}
//
} //func
//
// ********************************************************************************
// tab: StateHelp.pde
void drawForStateHelp() {
background(0);
// title
fill(WHITE);
int xpos= width/2;
int ypos=32;
textSize(29);
fill(WHITE);
textAlign(CENTER);
text("Help for the Program",
xpos, ypos);
textSize(14);
text("Polygon Editor",
xpos, ypos+33);
textAlign(LEFT);
// help text
text(helpText1, 122, 160,
610, 900);
}
// ********************************************************************************
// tab: StateMenu.pde
void showMenu() {
background (0);
// title
int xpos= width/2;
int ypos= 32;
textSize(29);
fill(WHITE);
textAlign(CENTER);
text("Main Menu. Needs a folder Polys in the Sketch Folder.",
xpos, ypos);
textAlign(LEFT);
// The core
mainMenu.display();
showStatusBar("Main Menu: Choose an Option. Press Space Bar to go to Editor. ");
}
//
// ********************************************************************************
// tab: StateSplash.pde
void drawForStateSplashScreen() {
// show splash screen
background(0);
showStatusBar("Press any key");
// yellow rectangle
final int rectWidth = 600;
fill(YELLOW);
noStroke();
rect(100, 260, rectWidth, 400);
// frame for the rect
int border = 4;
noFill();
stroke(0);
rect(100+border, 260+border,
rectWidth-2*border, 400-2*border);
// text in the rect
fill(0);
textSize(32);
textAlign(LEFT);
text("The Polygon Editor ", rectWidth/2+70, height/2-30,
300, 900);
textSize(14);
text(" Edit Polygons", rectWidth/2+90, height/2+40,
300, 900);
textSize(32);
}
//
// ********************************************************************************
// tab: Tools.pde
// General Tools
void burgerMenuSign() {
// Burger Menu Sign
fill(255);
textAlign(LEFT, TOP);
if (dist(mouseX, mouseY, burgerx1, burgery1) < 44)
stroke(0, 255, 0); // green
else
stroke(255); // white
strokeWeight(3);
float factorY = 9;
for (int i=0; i<3; i++) {
line(burgerx1+6, burgery1+8+i*factorY,
burgerx1+6+23, burgery1+8+i*factorY );
}//for
//reset
strokeWeight(1);
}
void showStatusBar(String s1) {
fill(111);
noStroke();
rect(0, height-20,
width, 22);
fill(WHITE);
textSize(14);
textAlign(LEFT);
text(s1, 6, height-4);
}
//--------------------------------------------------------
// ********************************************************************************
// tab: ToolsSaveLoad.pde
// the two 'callback' functions MUST BE OUTSIDE THE CLASS
// this tab is an addition to the class
void fileSelectedSave(File selection) {
// the 'callback' function
if (selection == null) {
// Window was closed or the user hit cancel
// go back
stateProgram=MENU;
} else {
// User selected selection.getAbsolutePath()
classSaveLoadTools.savePath=selection.getAbsolutePath();
}
}
void fileSelectedLoad(File selection) {
// the 'callback' function
if (selection == null) {
// Window was closed or the user hit cancel
// go back
stateProgram=MENU;
} else {
// User selected selection.getAbsolutePath()
classSaveLoadTools.loadPath=selection.getAbsolutePath();
}
}
//
// End of joined file. ********************************************************************************