here is another version
with
- auto upper case letter,
- multiple lines,
- Backspace and Delete working…
- mouse support,
- load and save
it’s a joined file that you can spread over multiple tabes
// ********************************************************************************
// joined pde-file of folder D:\Processing All\_General\Editor5
// ********************************************************************************
// ********************************************************************************
// tab: Editor5.pde main file (file name is folder name)
// Editor: using OWN class as Editor. NO libraries used.
// The core is the class TextBoxEditor.
//
// Demo for Editor and Save and load handling
// SEE 3 buttons.
// SKETCH EXPECTS A SUB FOLDER texts in the Sketch folder, see: final String pathFolder = "texts";
//
//
// from
// https : // forum.processing.org/two/discussion/comment/112902/#Comment_112902
// ---------------------------------------------------------------------------------------------------------------------------
// imports ---
// NONE
// classes ---
// Editor
TextBoxEditor textBoxEditor;
// Toolbox save / load
ClassSaveLoadTools classSaveLoadTools = new ClassSaveLoadTools();
// list of buttons
ArrayList<Button> listButton = new ArrayList();
// consts und vars ---
// Help
final String helpText = "--- EDITOR ---\n"
+"This editor does work only with java (default) and not with P2D or P3D / opengl.\n"
+"Use mouse to place cursor\nType text, use Backspace, Delete and Return\nUse Cursor up/down, left/right\nPos1, End\nCtrl-Pos1, Ctrl-End\nPg up, Pg Down\nctrl-y - delete current line\nCtrl-1 - test text";
// states of the program:
final int normal = 0; // unique constants
final int save = 1;
final int load = 2;
///current state (must be one of them)
int state=normal;
// -----------------------------------------------------------------------------------------------------------------------------------------------
// Core functions of processing
void setup() {
size(1800, 900);
this.registerMethod("keyEvent", this);
println(helpText.replace("\n", "\n * "));
// Create a text area (without horizontal and
// vertical scrollbars)
final String textToStart = "HELLO";
textBoxEditor = new TextBoxEditor( textToStart,
20, 20, // x, y
width-200, height-60, // width, height of the textBoxEditor
0300 << 030, color(255), // textColor, backgroundColor
color(-1, 0100), color(#FF00FF, 0200)); // bordColor, slctColor
// init buttons
String[] buttonTitles = {"Save", "Load", "New" };
int i=0;
for (String buttonTitle : buttonTitles) {
listButton.add(new Button (buttonTitle, width-70, 60+i*40, 50, 25));
i++;
}//for
}//func
void draw() {
switch (state) {
case normal:
//normal
drawForStateNormal() ;
break;
case save:
// wait for Save Dialog
classSaveLoadTools.waitForSaveDialog();
break;
case load:
// wait for Load Dialog
classSaveLoadTools.waitForLoadDialog();
break;
default:
//Error
println("Error: 4777");
exit();
break;
//
}//switch
//
}//func
//
// ********************************************************************************
// tab: classButton.pde
class Button {
String textButton;
PVector position = new PVector();
float sizeW, sizeH;
// constructor
Button ( String s1_,
float x_, float y_,
float sizeW_, float sizeH_ ) {
position.set(x_, y_);
sizeW = sizeW_;
sizeH = sizeH_;
textButton=s1_;
}// constructor
// ------------------------------------------
// methods
void display() {
// show button
// rect
stroke(200);
fill(255);
if (checkMouse())
fill(255, 0, 0);
if (checkMouse()&&mousePressed)
fill(255, 0, 120);
rect(position.x, position.y,
sizeW, sizeH);
// text
fill(0);
// text is centered
textAlign(CENTER);
text(textButton,
position.x+sizeW/2, position.y+17);
//reset
textAlign(LEFT);
}// method
boolean checkMouse() {
// returns true when inside
return
mouseX > position.x &&
mouseX < position.x + sizeW &&
mouseY > position.y &&
mouseY < position.y + sizeH;
} // method
//
}//class
//
// ********************************************************************************
// tab: classSaveLoad.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 = "texts";
final String fileExtension = ".txt";
// Paths (returned by 'callback' functions after using save and load)
String savePath="";
String loadPath="";
// no 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
state=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
state=load;
}
// ----------------------------------------------------
// waiting
void waitForSaveDialog() {
if (!savePath.equals("")) {
// waiting is over
saveIt();
// go back
state=normal;
}
}
void waitForLoadDialog() {
if (!loadPath.equals("")) {
// waiting is over
loadIt();
// go back
state=normal;
}
}
// ----------------------------------------------------
// executing save and load
void saveIt() {
// save
// split at line break and make array (to save it)
// get the data from the text Area
String[] strs = split(textBoxEditor.getText(), "\n" );
// 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, strs );
}
void loadIt() {
// load
String[] strs = loadStrings( loadPath );
String str1 = join(strs, "\n");
textBoxEditor.setText(str1);
}
//
}//class
//
// ********************************************************************************
// tab: classTextBoxEditor.pde
// Editor
class TextBoxEditor {
// debug
String testText = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aenean commodo ligula eget dolor. Aenean massa. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. "
+"Donec quam felis, ultricies nec, pellentesque eu, pretium quis, sem. Nulla consequat massa quis enim. Donec pede justo, fringilla vel, aliquet nec, vulputate eget, arcu. In enim justo, rhoncus ut, imperdiet a. "+
"venenatis vitae, justo. Nullam dictum felis eu pede mollis pretium. Integer tincidunt. Cras dapibus. Vivamus elementum semper nisi. Aenean vulputate eleifend tellus. Aenean leo ligula, porttitor eu, consequat vitae, "
+"eleifend ac, enim. Aliquam lorem ante, dapibus in, viverra quis, feugiat a, tellus. Phasellus viverra nulla ut metus varius laoreet. Quisque rutrum. Aenean imperdiet. Etiam ultricies nisi vel augue. Curabitur "
+"ullamcorper ultricies nisi. Nam eget dui. Etiam rhoncus. Maecenas tempus, tellus eget condimentum rhoncus. sem quam semper libero, sit amet adipiscing sem neque sed ipsum. Nam quam nunc, blandit vel, luctus pulvinar, "
+"hendrerit id, lorem. Maecenas nec odio et ante tincidunt tempus. Donec vitae sapien ut libero venenatis faucibus. Nullam quis ante. Etiam sit amet orci eget eros faucibus tincidunt. Duis leo. Sed fringilla mauris sit "
+"amet nibh. Donec sodales sagittis magna. Sed consequat, leo eget bibendum sodales, augue velit cursus nunc";
boolean ctrlIsDown=false;
color textColor, textBoxBackgroundColor,
borderColor, // not in use
selectedColor; // not in use
int x, y,
w, h;
// this is the entire text of the editor text area
String[] editorArray = new String[220];
// whether the blinking line is currently on or off
boolean showCursorAsLine=true;
// for cursor movements:
// When we use CRS up and down currentLine changes;
// for CRS left and right currentColumn changes.
int currentColumn = 0; // x-value measured in characters
int currentLine = 0; // y-value measured in lines
// when working within one line by CRS left and right, by backspace and by delete,
// the line is internally split up into 2 strings, which are left and right from the
// cursor. Thus it's easy to do backspace / delete within a line etc.
// See initNewLine() and others.
String leftText="", rightText="";
// ------------------------------------------------------
// constr
TextBoxEditor(String textIn_,
int xxIn_, int yyIn_,
int wwIn_, int hhIn_,
color textColorIn_, color textBoxBackgroundColorIn_,
color bordColorIn_, color slctColorIn_) { // not in use
x = xxIn_;
y = yyIn_;
w = wwIn_;
h = hhIn_;
textColor = textColorIn_;
textBoxBackgroundColor = textBoxBackgroundColorIn_;
// not in use
borderColor = bordColorIn_;
selectedColor = slctColorIn_;
setText(textIn_);
PGraphics dummy = new PGraphics();
// int keyCodePos1; int keyCodeEnd; int keyCodePageUp; int keyCodePageDown;
if (dummy.is3D()) {
// BAD
println("This editor does work only with java (default) and not with P2D or P3D / opengl. ");
exit();
} else {
//Good
}//else
} // constr
// ------------------------------------------------------
void setText(String text1_) {
editorArray = split(text1_, "\n");
currentLine=0;
initNewLine();
} // func
String getText() {
return
join(editorArray, "\n");
} // func
// ------------------------------------------------------
void display() {
// display Editor text box
// draw box
rectMode(CORNER);
noStroke();
fill(textBoxBackgroundColor);
rect(x, y, w, h);
// draw lines
textSize(14);
fill(textColor);
float textx=x+3;
float texty=y+2;
for (int i = 0; i < editorArray.length; i++) {
if (i==currentLine) {
// this is the current line of the cursor
text(leftText + rightText,
textx, texty,
w, h);
blinkingCursor(textx, texty);
} else {
// other lines
text(editorArray[i],
textx, texty,
w, h);
}
//next line
texty+=13;
}//for
//
}//method
// ------------------------------------------------------
// Inputs Keyboard and mouse
void keyPressedInClassEditor() {
if (key==CODED) {
// Coded
checkCodedKeys();
} else {
// NOT Coded
checkNotCodedKeys();
} // NOT Coded
//
} //func
void keyReleasedInClassEditor() {
final int keyCodeCtrl=17;
if (keyCode==keyCodeCtrl) {
ctrlIsDown=false;
}//if
} // func
void mouseInClassEditor() {
// use mouse to set cursor to a position
if (! overEditor() )
return;
textSize(14);
boolean done1=false;
boolean done2=false;
//currentColumn = 0;
//currentLine = 0;
// find currentLine of cursor position
int texty = y+2;
for (int i = 0; i < editorArray.length; i++) {
if (mouseY>texty &&
mouseY<texty+13) {
currentLine = i;
if (currentLine<0)
currentLine=0;
done1 = true;
break;
}//if
//next line
texty+=13;
}//for
if (! done1) // something went wrong
return;
// find currentColumn of cursor position
String currentText="";
for (int i = 0; i < editorArray[currentLine].length(); i++) {
// we check the width of the text letter by letter
float leftWidth = x+textWidth(currentText);
currentText += editorArray[currentLine].charAt(i);
float newWidth = x+textWidth(currentText);
if (mouseX > leftWidth &&
mouseX < newWidth) {
currentColumn = i;
initNewLine(); // currentColumn
done2=true;
break;
}//if
}//for
// when we didn't find a place to insert, we assume the end of the line
if (! done2) {
currentColumn = editorArray[currentLine].length();
initNewLine(); // currentColumn
}//if
//
}//method
// -----------------------------------------------------------------
// smaller funcs for keyboard
void checkNotCodedKeys() {
// not coded......
if (ctrlIsDown) {
// with control
if (key == '1') {
// Ctrl-1
testText=testText.replace(". ", ".\n");
setText(testText);
} else if (keyCode == 'Y') {
// Ctrl-y
deleteLine();
} else {
//
}
//
} else {
// without control
if (key == BACKSPACE) {
if (leftText.length()>0) {
leftText = leftText.substring(0, leftText.length()-1);
currentColumn--;
writeLineBackInArray();
} else {
// we are at start of line and with Backspace we move the entire current line to the end of the last line
currentColumn=0;
if (currentLine==0)
return;
int prevLengthPrevLine=editorArray[currentLine-1].length();
editorArray[currentLine-1]+=editorArray[currentLine];
deleteLine();
currentColumn = prevLengthPrevLine;
currentLine--;
initNewLine();
}
} else if (key == ENTER || key == RETURN) {
doReturnKey();
} else if (key == TAB) {
leftText += " ";
currentColumn+=4;
writeLineBackInArray();
} else if (key == DELETE) {
doDeleteKey();
} else if (key >= ' ') {
// Normal typing of text !!!!!
leftText += str(key);
leftText=leftText.toUpperCase();
currentColumn++;
writeLineBackInArray();
}
// ----
}//else without CTRL
}//method
void checkCodedKeys() {
// Coded
// CODED from now on.....
if (ctrlIsDown) {
// with control key
if (keyCode==36) {
// "Ctrl-Pos1"
writeLineBackInArray();
if (currentLine!=0)
currentLine=0;
else currentColumn=0;
initNewLine();
} else if (keyCode==35) {
// "Ctrl-End"
writeLineBackInArray();
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
// If we are not in last line
if (currentLine!=editorArray.length-1) {
currentLine=editorArray.length-1; // set current line to last line
} else {
currentColumn=editorArray[currentLine].length(); // if we are there already, set the column to end of line
}
initNewLine();
} else if (keyCode==33) {
//text1 = "Ctrl-Pg Up";
} else if (keyCode==34) {
//text1 = "Ctrl-Pg Down";
}
} else {
// without control key
if (keyCode == LEFT) {
decreaseCurrentColumn();
} else if (keyCode == RIGHT) {
increaseCurrentColumn();
} else if (keyCode == UP) {
// previous line in text
writeLineBackInArray();
currentLine--;
if (currentLine<0)
currentLine=0;
initNewLine(); // currentColumn
} else if (keyCode == DOWN) {
// next line in text
writeLineBackInArray();
currentLine++;
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
initNewLine(); // currentColumn
}
//---
else if (keyCode==36) {
// text1 = "Pos1";
currentColumn=0;
initNewLine();
} else if (keyCode==35) {
// text1 = "End";
currentColumn=editorArray[currentLine].length();
initNewLine();
} else if (keyCode==33) {
// text1 = "Pg Up";
currentLine-=4;
if (currentLine<0)
currentLine=0;
initNewLine();
} else if (keyCode==34) {
// text1 = "Pg Down";
currentLine+=4;
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
initNewLine();
}
//
}//else without control key
}//func
void doReturnKey() {
editorArray[currentLine]=leftText;
String[] newLineArray=new String[1];
newLineArray[0] = rightText;
// Splice one array of values into another
editorArray = splice(editorArray, newLineArray, currentLine+1);
currentLine++;
currentColumn = 0;
initNewLine();
}
void doDeleteKey() {
// Do delete key
if (rightText.length()-1>=0) {
// Delete char right of the cursor (normal situation)
rightText = rightText.substring(1); // remove 1st char in rightText
writeLineBackInArray();
} else {
//
writeLineBackInArray();
// rightText += editorArray[currentLine+1];
int prevLengthPrevLine=editorArray[currentLine].length();
if (editorArray.length<=1)
return;
if (currentLine+1>=editorArray.length)
return;
editorArray[currentLine] += editorArray[currentLine+1];
// writeLineBackInArray();
currentLine++;
deleteLine();
writeLineBackInArray();
currentLine--;
currentColumn=prevLengthPrevLine;
initNewLine();
// writeLineBackInArray();
}//else
//
}//method
// -------------------------------------------------------------------
boolean overEditor() {
if (mouseX >= x &&
mouseX <= x+w &&
mouseY >= y &&
mouseY <= y+h) {
return true;
} else {
return false;
}
} // method
void spliceNewTextIntoEditor (String[] newArray) {
// Splice one array of values into another.
// (This can be used when we load a second file and insert it in the editor at cursor position.)
// Not in use.
editorArray = splice(editorArray, newArray, currentLine);
} // method
void initNewLine() {
// when entering a new line
// we set left and right String leftText and rightText
// when column # too small, fix it
if (currentColumn<0) {
currentColumn=0;
}
// when no text is present, we make an empty text
if (editorArray.length<=0) {
editorArray=new String[1];
editorArray[0]="";
}
//if line number is too high, fix it
if (currentLine>editorArray.length-1)
currentLine=editorArray.length-1;
// column is too low, fix it
if (currentLine<0)
currentLine=0;
if (currentColumn > editorArray[currentLine].length()) {
currentColumn=editorArray[currentLine].length(); //-1? ???
if (currentColumn<0)
currentColumn=0;
}
// set left and right String
leftText = editorArray[currentLine].substring( 0, currentColumn);
rightText = editorArray[currentLine].substring( currentColumn );
//
} // method
void writeLineBackInArray() {
// when leaving a line, the leftText + rightText needs to go back in the array
editorArray[currentLine] = leftText + rightText;
} // method
void decreaseCurrentColumn() {
currentColumn--;
if (currentColumn<0)
currentColumn=0;
initNewLine();
} // method
void increaseCurrentColumn() {
currentColumn++;
if (currentColumn>editorArray[currentLine].length())
currentColumn=editorArray[currentLine].length();
// initNewLine();
leftText = editorArray[currentLine].substring( 0, currentColumn);
rightText = editorArray[currentLine].substring( currentColumn );
} // method
void blinkingCursor( float textx, float texty) {
if ((frameCount%11) == 0) {
showCursorAsLine= ! showCursorAsLine;
}
if (showCursorAsLine) {
float leftWidth = textWidth(leftText);
stroke(255, 0, 0);
strokeWeight(1);
line(textx+leftWidth, texty,
textx+leftWidth, texty+19);
stroke(0);
}
} // method
void newText() {
// New
// editorArray = split(text1, "\n");
editorArray = split("Hello", "\n");
currentLine=0;
currentColumn=0;
initNewLine();
} // method
void deleteLine() {
// delete line
writeLineBackInArray();
String[] before = (String[]) subset(editorArray, 0, currentLine);
String[] after = (String[]) subset(editorArray, currentLine+1);
editorArray = (String[]) concat(before, after);
initNewLine();
} // method
//
}//class
//
// ********************************************************************************
// tab: InputsKeys.pde
// Inputs Keyboard
void keyPressed() {
switch (state) {
case normal:
if (key==ESC) {
key=0; // kill
}
// editor codes !
textBoxEditor.keyPressedInClassEditor();
break;
case save:
case load:
// ignore
break;
default:
// Error
println("Error 975: "+"unknown state "+(state));
exit();
break;
}//switch
//
} //func
public void keyEvent(KeyEvent ke) {
if (ke.getAction() == KeyEvent.PRESS) {
textBoxEditor.ctrlIsDown = (ke.getModifiers() & KeyEvent.CTRL) == KeyEvent.CTRL;
}
}
void keyReleased() {
if (state!=normal)
return;
// editor codes !
textBoxEditor.keyReleasedInClassEditor();
} // func
// ********************************************************************************
// tab: InputsMouse1.pde
// Inputs mouse
void mousePressed() {
if (state!=normal)
return;
String command="";
// for the buttons
for (Button currentButton : listButton) {
if (currentButton.checkMouse()) {
command=currentButton.textButton;
break;
}//if
} //for
// found a mouse button like save/load/new
if (! command.equals("")) {
// execute
doCommand(command);
} else {
// editor :
textBoxEditor.mouseInClassEditor();
}//else editor
//
} //func
// --------------------------------------------------------------------------------
void doCommand(String command) {
//
if (command.equals(""))
return;
switch(command) {
case "Load":
classSaveLoadTools.initLoad();
break;
case "Save":
classSaveLoadTools.initSave();
break;
case "New":
textBoxEditor.newText();
break;
default:
// Error
println("unknown command "+command);
exit();
break;
}//switch
//
} //func
//
// ********************************************************************************
// tab: States.pde
// The states of the program
void drawForStateNormal() {
background(0);
// title
fill(255, 2, 2);
textSize(14);
text("Little Editor",
width-133, 20,
130, 422);
// buttons
for (Button currentButton : listButton) {
currentButton.display();
} //for
// show Editor Text Box
textBoxEditor.display();
textSize(24);
//
}
//
// ********************************************************************************
// 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
state=normal;
} 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
state=normal;
} else {
// User selected selection.getAbsolutePath()
classSaveLoadTools.loadPath=selection.getAbsolutePath();
}
}
//
// End of joined file. ********************************************************************************