Some Graphical Editors I made

Some Graphical Editors (for all editors see the link below) :

  • my Bezier Editor: here you can draw beziers with the mouse and the sketch generates your code that you can use in the other sketch (your target sketch)

  • another version: like the above but you can now add points BETWEEN existing points and you can also select GROUPS of points (button “Select”) and then drag the entire group (button “Drag”)

  • Similar to the programs above, I made a shape / PShape editor, where you can draw by clicking the mouse and then export an entire sketch including the drawn PShape.

  • graphical Editor for shapes in 2D: you can enter points with the mouse and separately connect them to shapes - in 2D - export as new sketch

  • graphical Editor for shapes in 3D. you can enter points with the mouse, edit them in 3D and separately connect them to shapes - in 3D - export as new sketch

See:

3 Likes

Here is a 3D Editor with 3D cursor and 3 different views

I am willing to share all the Code for the movies, just ask

Chrisir

1 Like

Amazing…

see 3d drawing with mouse - #7 by Chrisir

1 Like

A Polygon Editor for 2D with a full Menu and Load and Save


// ********************************************************************************
//         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)
// The states correspond to the Main Menu (Splash Screen, Menu State, then the entries of the Menu):
final int SPLASH_SCREEN         = 0; // Yellow start Screen
final int MENU                  = 1; // MAIN MENU
final int AddPoints             = 6; // add points with mouse click (for empty canvas)
final int EDITOR                = 2; // drag points, delete points, show as shape
final int STATE_MOVE            = 7; // move entire shape
final int LOAD                  = 5; // load
final int SAVE                  = 4; // save
final int HELP                  = 3; // help
int stateProgram = SPLASH_SCREEN; // current state

// Texts for main menu buttons
final String[] textsForMenu = {
  "Add points",
  "Editor: Move and delete points",
  "Move entire polygon",
  "Load ",
  "Save ",
  "Help Screen",
  "Delete All"
};

// colors
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

// The Polygon
ArrayList<PVector> polygon = new ArrayList();

// Toolbox save / load
ClassSaveLoadTools classSaveLoadTools;

// Menu
Menu mainMenu;

float burgerX= 20, burgerY= 20;

// Help
String helpTextEditor    = "Burger Icon goes back to Menu\nEsc goes back to Menu\n1 Toggle Shape\nBackspace delete last point\nx Toggle Help";
String helpTextStateHelp = "Polygon Editor\nEsc goes back to Menu normally";
boolean showHelp = true;

boolean showAsShape = false; // for state Editor

// dragging points
boolean mouseDragForStateEditor = false;  // for State Editor
int selectedPointForStateEditor = -1;     // for State Editor

// dragging polygon
boolean mouseDragForStateMove   = false;  // for state STATE_MOVE

// -------------------------------------------------------------------------------------

void settings() {
  size( 1200, 900 );
}

void setup() {
  surface.setTitle("Polygon Editor");

  //font
  PFont pf = createFont("ARIAL", 14);
  textFont(pf);

  // load and save Toolbox
  classSaveLoadTools = new ClassSaveLoadTools();

  // Main Menu
  mainMenu = new Menu();
} // setup

void draw() {

  switch(stateProgram) {

  case SPLASH_SCREEN:
    drawForStateSplashScreen();
    break;

  case MENU:
    showMenu();
    break;

  case AddPoints:
    drawForStateAddPoints();
    break;

  case EDITOR:
    drawForStateEditor();
    break;

  case STATE_MOVE:
    // move entire shape
    drawForStateMove();
    break;

  case LOAD:
    // wait for Load Dialog
    classSaveLoadTools.waitForLoadDialog();
    break;

  case SAVE:
    // wait for Save Dialog
    classSaveLoadTools.waitForSaveDialog();
    break;

  case HELP:
    drawForStateHelp();
    break;

  default:
    // ERROR
    println("draw(): Error 31223 with "+stateProgram);
    exit();
    break;
  } //switch
  //
} // draw
//

// ********************************************************************************
// tab: cMenu.pde


// this is the Main Menu on the center

class Menu {

  final int myButtonsWidth = 430;

  final int x1 = int(width/2.0- myButtonsWidth/2.0);
  final int y1 = 110;

  final color bkColor = color(133);

  boolean open=true;

  // 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,
      // visible, text from elementsForMenu, id from i
      myButtons[i] = new Button(
        x1+10, (y1+30) + i * 75,
        myButtonsWidth, 50,
        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() {
    int result = -1;

    for (Button btn : myButtons) {
      if (btn.myMousePressed()) {
        result = btn.id;
      }//if
    }//for

    return result;
  }//method
  //
} // class
//

// ********************************************************************************
// tab: cMenuButton.pde



class Button {

  // only used for Menu

  int x, y,
    w, h,
    id;
  boolean vis;
  String text;

  // constr
  Button(int x, int y,
    int w, int h,
    boolean vis,
    String text_,
    int id) {
    //
    this.x = x;
    this.y = y;
    this.w = w;
    this.h = h;
    this.vis       = vis;
    this.text      = text_;
    this.id        = id;
  } // constr

  void  draw() {
    if ( vis ) {
      strokeWeight(1);

      fill(0, 0, 200);

      if (over())  stroke(200, 0, 200);
      else         stroke(0, 200, 200);

      rect(x, y,
        w, h);

      noStroke();
      fill(200);
      textAlign(LEFT, TOP);
      text(text,
        x + 4, y + 3,
        w-10, 900);
    }
  }

  boolean over() {
    return
      mouseX > x &
      mouseX < x + w &
      mouseY > y &
      mouseY < y + h;
  }

  boolean myMousePressed() {
    //called from main mousePressed
    return
      over();
  }
  //
} // class
//

// ********************************************************************************
// tab: cSaveLoad.pde


// Save and load class.

// Remark: the two 'callback' functions MUST BE OUTSIDE THE CLASS.
// Class with 3 blocks with 2 functions each, for save and load.

class ClassSaveLoadTools {

  // editor path and file extension
  final String pathFolder    = "Polys";
  final String fileExtension = ".csv";

  // Paths (returned by 'callback' functions after using save and load)
  String savePath="";
  String loadPath="";

  // --------------------------------------------------------------------

  // constr
  ClassSaveLoadTools() {
    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=MENU;  // stateProgram=EDITOR;
    }
  }

  // ----------------------------------------------------
  // executing save and load [AFTER the 2 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() {
    // load

    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 ( float(  elementsInLine[0]), float(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) {
      // ignore
    } else if (key=='0') {
      // dump
      for (PVector pv : polygon) {
        println(pv.x
          +","
          +pv.y);
      }
    }
    key=0;  //  kill ESC
    break;

  case STATE_MOVE:
  case HELP:
    key=0;             //  kill ESC
    stateProgram=MENU; // leave state
    break;

  case EDITOR:
    if (key==DELETE&&mouseDragForStateEditor&&selectedPointForStateEditor!=-1) {
      polygon.remove(selectedPointForStateEditor);
      mouseDragForStateEditor=false;
      selectedPointForStateEditor=-1;
    } else if (key==ESC) {
      key=0;  //  kill ESC
      stateProgram=MENU; // leave state
    } else if (key=='1') {
      showAsShape =
        !showAsShape;
    } else if (key=='x') {
      showHelp =
        ! showHelp;
    } else if (key==BACKSPACE) {
      if (polygon.size()>0)
        polygon.remove(polygon.size()-1);
    }
    break;

  case AddPoints:
    if (key==ESC) {
      key=0;  //  kill ESC
      stateProgram=MENU; // leave state
    } else if (key==BACKSPACE) {
      if (polygon.size()>0)
        polygon.remove(polygon.size()-1);
    }
    break;

  default:
    // ERROR
    println("keyPressed(): Error 227 with "+stateProgram);
    exit();
    break;
  }//switch
  //
}//func
//

// ********************************************************************************
// 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;

  case STATE_MOVE:
    //
    mouseDragForStateMove=true;
    break;

  default:
    println("Error 129");
    exit();
    break;
  }//switch
}

void mouseReleased() {
  mouseDragForStateEditor=false;
  mouseDragForStateMove  =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:
    // MOVE
    stateProgram=STATE_MOVE;
    break;

  case 3:
    // load
    classSaveLoadTools.initLoad();
    break;

  case 4:
    // SAVE dialog
    classSaveLoadTools.initSave();
    break;

  case 5:
    stateProgram=HELP;
    break;

  case 6:
    // delete all
    polygon.clear();
    break;

  default:
    println("mousePressedForStateMENU(): 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 only from here on

  // are we already dragging?
  if (mouseDragForStateEditor) {
    return; // leave
  }

  // Burger Menu
  if (dist(mouseX, mouseY, burgerX, burgerY) < 44) {
    stateProgram=MENU;
    return;
  }

  // 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) {
      selectedPointForStateEditor = i;
      mouseDragForStateEditor=true;
      return;
    }//if
  }//for

  // Hide Help Text
  if (dist(mouseX, mouseY, 22, 100) < 22) {
    showHelp =
      ! showHelp;
  }//if
  //
}//func
//

// ********************************************************************************
// tab: StateAddPoints.pde



void drawForStateAddPoints() {
  background(0);

  // title
  showTitle("Add points", "Click in the canvas");

  showPoly();

  showPolySize();

  showStatusBar("Click Mouse to add points. Backspace to delete last point. Esc for Menu.");
}

// ********************************************************************************
// tab: StateEditor.pde



// for state Editor

void drawForStateEditor() {
  // draw For State "Editor"

  background(0);

  showStatusBar("Burger Symbol for Menu. Press 1 for Shape on/off. Backspace to delete the last point. Press x to toggle help.");

  if (showAsShape) {
    fill(111);
    beginShape();
    for (PVector pv : polygon) {
      vertex(pv.x, pv.y);
    }
    endShape();
  }//if

  showPoly();

  if (mouseDragForStateEditor) {
    polygon.get(selectedPointForStateEditor).x=mouseX;
    polygon.get(selectedPointForStateEditor).y=mouseY;

    PVector pv = polygon.get(selectedPointForStateEditor);

    showStatusBar("Drag. DEL to delete. Pos: "
      +pv.x + ", "+pv.y);
  }

  //-------------------

  showTitle("Points Editor", "Drag Points (drag and press delete key to delete the point)");

  // burger menu
  burgerMenuSign();

  // Message
  showPolySize();

  // small help text, top left
  fill(255);
  if (showHelp) {
    text(helpTextEditor,
      22, 100,
      310, 900);
  } else {
    if (dist(mouseX, mouseY, 22, 100) < 22) {
      fill(0, 255, 0);
    }
    text("x",
      22, 100);
  }
  //
} //func
//

// ********************************************************************************
// tab: StateHelp.pde



void drawForStateHelp() {
  background(0);

  // title
  showTitle("Help for the Program", "Polygon Editor");

  // help text
  text(helpTextStateHelp, 122, 160,
    610, 900);
}

// ********************************************************************************
// tab: StateMenu.pde



void showMenu() {

  background (0);

  // title
  showTitle("Main Menu", "Requires Sub folder Polys in Sketch's folder.");

  // The core
  mainMenu.display();

  // number of points
  showPolySize();

  // status bar
  showStatusBar("Main Menu: Choose an Option. Press Space Bar to go to Editor. ");
}
//

// ********************************************************************************
// tab: StateMove.pde



void drawForStateMove() {
  // move entire shape
  background(0);

  if (mouseDragForStateMove) {
    for (PVector pv : polygon) {
      pv.x+=mouseX-pmouseX;
      pv.y+=mouseY-pmouseY;
    }
  }

  // title
  showTitle("Move entire polygon", "Click anywhere in the canvas and drag");

  showPoly();

  showPolySize();

  showStatusBar("Use Mouse to move. Esc for Menu.");
}

// ********************************************************************************
// tab: StateSplash.pde



void drawForStateSplashScreen() {

  // show splash screen
  background(0);

  showStatusBar("Click mouse.");

  // 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. \nRequires Sub-folder 'Polys' in Sketch's folder.",
    rectWidth/2+70, height/2+40,
    300, 900);
  textSize(32);
}
//

// ********************************************************************************
// tab: Tools.pde


// General Tools

void showTitle(String headline, String subText ) {
  // title
  int xpos= width/2;
  int ypos=32;
  textSize(29);
  fill(WHITE);
  textAlign(CENTER);
  text(headline,
    xpos, ypos);
  textSize(14);
  text(subText,
    xpos, ypos+33);
  textAlign(LEFT);
}

void burgerMenuSign() {
  // Burger Menu Sign

  fill(255);
  textAlign(LEFT, TOP);

  if (dist(mouseX, mouseY, burgerX, burgerY) < 44)
    stroke(0, 255, 0); // green
  else
    stroke(255); // white

  strokeWeight(3);

  float factorY = 9;
  for (int i=0; i<3; i++) {
    line(burgerX+6, burgerY+8+i*factorY,
      burgerX+6+23, burgerY+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);
}

void showPolySize() {
  textSize(14);
  fill(255);
  textAlign(LEFT);
  text ("Number of Points:\n"
    +polygon.size(),
    width-141, height-210);
}

void showPoly() {
  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);
  }
}

// ********************************************************************************
// 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. ********************************************************************************


2 Likes