Text editor base?

Hey! So I’m trying to make a text editor in processing something similar to Notepad++ but simpler. Here is what I got so far:

PFont font;

PImage save;
PImage open;
PImage brush;

color theme1 = color(0, 8, 48);
color theme2 = color(0, 7, 30);

boolean bluet = true;
boolean darkt = false;

int scrolli = 0;
float scrolli2;

Line l1 = new Line(40, 1);

Toolbar t = new Toolbar();

Scrollbar sb = new Scrollbar(585, 50, 350, 60);

RMBMenu r = new RMBMenu();

ArrayList<Line> lines;

void setup() {
  size(600, 400);
  surface.setTitle("EpicTextEditor v0.1");

  font = loadFont("SourceCodePro-Regular-48.vlw");
  textFont(font);

  //save = loadImage("saveIcon.png");
  //open = loadImage("openIcon.png");
  //brush = loadImage("brushIcon2.png");

  lines = new ArrayList<Line>();
}

void draw() {
  background(theme1);
  
  //themes
  if (darkt == true) {
    theme1 = color(70);
    theme2 = color(30);
  }

  for (int i = 1; i <= 50; i++) {
    lines.add(new Line(i * 20 + 30, i));
    Line l = lines.get(i - 1);
    l.y = sb.setScrollObjectY(0, 650) + (i * 20 + 30);
  }

  for (int i = 1; i <= 50; i++) {
    Line l = lines.get(i - 1);
    l.display();
  }

  t.display();

  sb.display();

  r.display();
}

void mousePressed() {
  sb.mousePress();
  r.mousePress();

  for (int i = 1; i <= 50; i++) {
    Line l = lines.get(i - 1);
    l.mousePress();
  }
}

void mouseReleased() {
  sb.mouseRelease();
}

void keyPressed() {
  for (int i = 1; i <= 50; i++) {
    Line l = lines.get(i - 1);
    l.keyPress();
  }
}

void mouseDragged() {
  for (int i = 1; i <= 50; i++) {
    Line l = lines.get(i - 1);
    l.mouseDrag();
  }
}

void mouseWheel(MouseEvent event) {
  scrolli = constrain(scrolli + event.getCount(), 0, 50);
  scrolli2 = map(scrolli, 0, 30, 70, 220);
  sb.sy = int(scrolli2);
}

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

class Line {

  String text = "";

  boolean selected;

  float yCtrl;
  float y;
  int n;

  boolean blink = true;
  int t = 0;

  Line(float y1, int n1) {
    y = y1;
    n = n1;
  }


  void display() {
    fill(theme1);
    noStroke();
    rect(0, y, width, 20);

    fill(theme2);
    rect(0, y, 40, 20);

    if (selected == true) {
      fill(0, 110);
      rect(0, y, width, 20);

      //blinking line
      fill(255);
      textSize(14);
      t++;
      if (t > 30) {
        blink = !blink;
        t = 0;
      }
      if (blink == true) text("|", 43 + textWidth(text), y + 15);
      if (keyPressed) {
        blink = true;
        t = 0;
      }
    } else t = 0;

    fill(150);
    textSize(14);
    text(nf(n, 3), 7, y + 15);

    fill(255);
    textSize(14);
    text(text, 43, y + 15);
  }
  
  int getn() {
    if (selected == true) return n;
    else return -1;
  }

  void mousePress() {
    if (selected == true && r.displayb == true && mouseX > r.x && mouseX < r.x + 160 && mouseY > r.y + 42 && mouseY < r.y + 58) text = "";
    
    if (r.displayb == false) {
      if (mouseButton == LEFT) {
        if (mouseY > 50 && mouseY > y && mouseY < y + 20 && mouseX < 585) selected = true; 
        else if (mouseX < 585) selected = false;
      } else if (mouseButton == CENTER) {
        if (mouseY > 50 && mouseY > y && mouseY < y + 20 && mouseX < 585) selected = true;
      }
    }
  }

  void keyPress() {
    if (selected == true) {
      if (key != ENTER) {
        if (key==BACKSPACE) {
          if (text.length()>0) {
            text=text.substring(0, text.length()-1);
          }
        } else if (key != CODED && textWidth(text) < 532) {
          text+=key;
        }
      }
    }
  }

  void mouseDrag() {
    if (r.displayb == false) {
      if (mouseButton == CENTER || mouseButton == LEFT) {
        if (sb.scroll == false && mouseX < 585 && mouseY > y && mouseY < y + 20) {
          selected = true;
          blink = true;
        }
      }
    }
  }
}

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

class RMBMenu {

  int x = 0;
  int y = 0;

  boolean displayb = false;

  RMBMenu() {
  }

  void display() {
    if (displayb == true) {   
      stroke(150);
      fill(200);
      rect(x, y, 160, 60);

      line(x + 20, y + 2, x + 20, y + 58);
      
      //copy
      fill(0);
      textSize(14);
      text("Copy",x + 26, y + 15);
      
      noStroke();
      fill(0, 142, 237,100);
      if (mouseX > x && mouseX < x + 160 && mouseY > y + 2 && mouseY < y + 18) rect(x,y + 2,160,16);
      
      //paste
      fill(0);
      textSize(14);
      text("Paste",x + 26, y + 35);
      
      noStroke();
      fill(0, 142, 237,100);
      if (mouseX > x && mouseX < x + 160 && mouseY > y + 22 && mouseY < y + 38) rect(x,y + 22,160,16);
      
      //delete
      fill(0);
      textSize(14);
      text("Delete",x + 26, y + 55);
      
      noStroke();
      fill(0, 142, 237,100);
      if (mouseX > x && mouseX < x + 160 && mouseY > y + 42 && mouseY < y + 158) rect(x,y + 42,160,16);
    }
  }

  void mousePress() {
    if (mouseX > x && mouseX < x + 160 && mouseY > y + 42 && mouseY < y + 58);
    
    if (mouseButton == RIGHT) {
      x = mouseX;
      y = mouseY;
      displayb = true;
    }

    if (mouseButton == LEFT) {
      if (displayb == true && mouseX > x && mouseY > y && mouseX < x + 160 && mouseY < y + 60) {
      } else displayb = false;
    }
  }
}

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

class Scrollbar {
  public int x;
  public int y;
  public int h;

  public int sy;
  public int sh;

  public color c = color(130);

  public boolean scroll = false;

  Scrollbar(int x1, int y1, int h1, int sh1) {
    x = x1;
    y = y1;
    h = h1;
    sy = y1 + 20;
    sh = sh1;
  }

  void display() {
    //base
    fill(200);
    noStroke();
    rect(x, y, 15, h);
    
    //up and down arrows
    fill(130);
    triangle(x + 3, y + 12, x + 12, y + 12, x + 8, y + 6);
    triangle(x + 3, y + h - 12, x + 12, y + h - 12, x + 8, y + h - 6);
    
    fill(160,140);
    if (scroll == true || mouseX > x && mouseX < x + 15 && mouseY > y && mouseY < y + 20) rect(x,y,15,20);
    if (scroll == true || mouseX > x && mouseX < x + 15 && mouseY > y + h - 20 && mouseY < y + h) rect(x,y + h - 20,15,20);

    //scrollbar
    fill(c);
    noStroke();
    rect(x, sy, 15, sh);
    strokeWeight(1);
    stroke(80);
    line(x + 4, sy + sh/2 - 5, x + 11, sy + sh/2 - 5);
    line(x + 4, sy + sh/2, x + 11, sy + sh/2);
    line(x + 4, sy + sh/2 + 5, x + 11, sy + sh/2 + 5);

    if (mouseX > x && mouseX < x + 15 && mouseY > sy && mouseY < sy + sh || scroll == true) c = color(160);
    else c = color(130);
    if (scroll == true) {
      sy = mouseY - sh/2;
      scrolli = int(map(sy,70,220,0,30));
    }
    if (sy <= y + 20) sy = y + 20;
    if (sy + sh >= y + h - 20) sy = (y + h - 20) - sh;
  }
  
  void mouseScroll() {
    
  }

  void mousePress() {
    if (sy != y + 20 && mouseX > x && mouseX < x + 15 && mouseY > y && mouseY < y + 20) sy = sy - 20;
    if (sy != (y + h - 20) - sh && mouseX > x && mouseX < x + 15 && mouseY > y + h - 20 && mouseY < y + h) sy = sy + 20;
    
    if (mouseX > x && mouseX < x + 15 && mouseY > sy && mouseY < sy + sh ) {
      scroll = true;
    }
  }

  void mouseRelease() {
    scroll = false;
  }

  int getY() {
    return(sy - 20);
  }

  float setScrollObjectY(int y1, int y2) {
    return(-map(getY(), y, (y + h) - (sh + 40), y1, y2));
  }
}

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

class Toolbar {
  
  Toolbar() {
    
  }
  
  
  void display() {
    fill(theme2);
    noStroke();
    rect(0,0,width,50);
    
    stroke(theme1);
    strokeWeight(5);
    line(0,41,width,41);
    
    ////save button
    //image(save,10,7,25,25);
    
    ////open button
    //image(open,50,6,27,25);
    
    ////seperator1
    //stroke(130);
    //strokeWeight(1);
    //line(87,7,87,32);
    
    ////brush button
    //image(brush,97,6,27,27);
  }
  
}

//end

I have a question about the base of the sketch. Right now the base is basically: there is a line class which holds a string that you can edit if the line is selected. There are bunch of lines and you can select multiple lines at the same time.

Well it works but I feel like it doesn’t have much potential for other text editor stuff like selecting text or moving the line between characters.And it currently doesn’t go to the next line when you hit enter, I tried stuff but couldn’t really figured it out.

My question is what kind of a base should I use? Does this system have potential should I stick with it or should I hold all the text in a single string or should I hold all the characters typed in an array or something else? How does notepad++ do it for example?

Also @Brastin , in your Processing OS (which is absolutely amazing btw) you have a text editor. How did you do the base?

Thanks!

1 Like

I hope I don’t come over too negative, but why begin by trying to replicate that we already have, in spades? Whilst it’s good to try and “make a thing”, if you begin from what we already have, you will innevitably be held hostage by all that is bad about text editors. You will end making a sub-standard version of what we already have working.

And the Brasin OS is a lovely nonsense. We don’t need a pretend operating system, and even MacOS itself is failing to build on its great work in 1987. Very little has moved on. It’s stale.

I would argue that Processing/p5js is a tool for you to bring NEW IDEAS into life.

Might I suggest that you checkout the Lifestreams concept https://www.wired.com/1997/02/lifestreams/ or Jef Raskin has ideas for an OS called LEAP, a text editor but not, a programming language, way of navigating… and check this… I just downloaded it… wild!
https://apps.apple.com/app/raskin/id404175816?mt=12&ls=1 …/ but LEAP was perhaps more like this… https://github.com/hundredrabbits/Left

History is littered with fabulous ideas that didn’t, and couldn’t, quite work, but we are living in different times now. Maybe your next “text editor” will blow the doors off writing somehow in ways Notepad won’t :slight_smile:

Good luck.

with base you mean something like “basic concept” or “general approach”, right?

Remark 1

Woe, you can’t do this inside draw() :

 for (int i = 1; i <= 50; i++) {
    lines.add(new Line(i * 20 + 30, i));

Within seconds you have 19000 lines !

Do it in setup()

Remark 2

Your variable / object names are often too short: t, sb, r - it saves you a tiny bit of typing time but will cost you a lot of time to understand your code later!

Remark 3

This is not good:

  for (int i = 1; i <= lines.size(); i++) { // ??????
    Line l = lines.get(i - 1);
    l.mousePress();

ArrayLists start at 0 so just start i with 0 and get rid of -1 in get(i - 1) also (and < instead of <=)

  for (int i = 0; i < lines.size(); i++) {
    Line l = lines.get( i );
    l.mousePress();

OR just :

void keyPressed() {
  for (Line l : lines) {
    l.keyPress();
  }
}

Remark 4

if (darkt == true) {

same as

if (darkt) {

Remark 5

if (darkt == false ) {

same as

if ( ! darkt ) {

Remark 6

Instead of searching the selected line number

  for (Line l : lines) {
    l.keyPress();  // only the selected line does something here!!!! 
  }

we could store the line number of the selected line.

No for-loop needed:

lines.get( numberOfTheSelectedLine ).keyPress();

Remark 7

I made a new version below.

I made a few changes.

I did key ENTER and UP and DOWN ( LEFT and RIGHT have to be done inside the class )

Warm regards,

Chrisir



PFont font;

PImage save;
PImage open;
PImage brush;

color theme1 = color(0, 8, 48);
color theme2 = color(0, 7, 30);

boolean bluet = true;
boolean darkt = false;

int scrolli = 0;
float scrolli2;

Line l1 = new Line(40, 1);

Toolbar t = new Toolbar();

Scrollbar sb = new Scrollbar(585, 50, 350, 60);

RMBMenu rmbMenu = new RMBMenu();

ArrayList<Line> lines;

final int distFromTop = 60; 

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

void setup() {
  size(600, 400);
  surface.setTitle("EpicTextEditor v0.1");

  font = createFont("SourceCodePro-Regular-48.vlw", 14);
  textFont(font);

  //save = loadImage("saveIcon.png");
  //open = loadImage("openIcon.png");
  //brush = loadImage("brushIcon2.png");

  lines = new ArrayList<Line>();

  for (int i = 0; i <= 5; i++) {
    lines.add(new Line(i * 20 + distFromTop, i));
  }
}//setup

void draw() {

  // themes
  if (darkt == true) {
    theme1 = color(70);
    theme2 = color(30);
  }

  background(theme1);

  for (int i = 0; i < lines.size(); i++) {
    Line l = lines.get(i);
    l.yPos = sb.setScrollObjectY(0, 650) + (i * 20 + distFromTop);
  }

  for (int i = 0; i < lines.size(); i++) {
    Line l = lines.get(i);
    l.display();
  }

  t.display();

  sb.display();

  // rmbMenu.display();

  fill(255);
  text ("lines: "
    +  lines.size(), 
    33, 33 ) ;
}//draw

// ------------------------------------------------------------------------------------
// Inputs mouse 

void mousePressed() {
  sb.mousePress();
  rmbMenu.mousePress();

  for (int i = 0; i < lines.size(); i++) {
    Line l = lines.get(i);
    l.mousePress();
  }
}

void mouseReleased() {
  sb.mouseRelease();
}

void mouseDragged() {
  for (int i = 0; i < lines.size(); i++) {
    Line l = lines.get(i);
    l.mouseDrag();
  }
}

void mouseWheel(MouseEvent event) {
  scrolli = constrain(scrolli + event.getCount(), 0, 50);
  scrolli2 = map(scrolli, 0, 30, 70, 220);
  sb.sy = int(scrolli2);
}

//--------------------------------------------------------------------------
// Inputs keyboard 

void keyPressed() {

  // We eval key ENTER and UP and DOWN (LEFT and RIGHT have to be done inside the class) here (basically ALL keys that change the current line number we are in)

  if (key == ENTER || key == RETURN) {
    // ENTER
    key=0; 
    for (int i = 0; i < lines.size(); i++) {
      if ( lines.get(i).selected ) {
        // we have the selected line
        lines.get(i).selected = false;
        if (i==lines.size()-1) {
          // add at end 
          lines.add(new Line(i * 20 + 30, i+1));
          lines.get(i+1).selected=true;
        } else {
          // add in the middle of ArrayList (at position i) 
          lines.get(i).selected = false;
          lines.add(i+1, new Line(i * 20 + 30, i+1));
          lines.get(i+1).selected=true;
          // when inserting, increase the line numbers below 
          for (int i2 = i+1; i2 < lines.size(); i2++) {
            lines.get(i2).n=i2;
          }
        }
        return; // leave
      }
    }
    return; // leave
  } 

  if (keyCode == UP) {
    // UP 
    for (int i = 0; i < lines.size(); i++) {
      if ( lines.get(i).selected ) {
        // we have the selected line
        if (i>0) {
          // act now 
          lines.get(i).selected = false;
          lines.get(i-1).selected = true;
          return; // leave
        }
      }
    }
    return; // leave
  } else if (keyCode == DOWN) {
    for (int i = 0; i < lines.size(); i++) {
      if ( lines.get(i).selected ) {
        if (i<lines.size()-1) {
          // act now 
          lines.get(i).selected = false;
          lines.get(i+1).selected = true;
          return; // leave
        }
      }
    }
    return; // leave
  }

  // other keys are passed into the object 
  for (Line l : lines) {
    l.keyPress();
  }//for
}//func 

// ===========================================================================
// classes 

class Line {

  String text = "";

  boolean selected;

  float yCtrl;
  float yPos;
  int n;

  boolean blink = true;
  int t = 0;

  Line(float y1, int n1) {
    yPos = y1;
    n = n1;
  }

  void display() {
    fill(theme1);
    noStroke();
    rect(0, yPos, width, 20);

    fill(theme2);
    rect(0, yPos, 40, 20);

    if (selected) {
      fill(0, 110);
      rect(0, yPos, width, 20);

      //blinking line
      fill(255);
      textSize(14);
      t++;
      if (t > 30) {
        blink = !blink;
        t = 0;
      }
      if (blink) 
        text("|", 
          43 + textWidth(text), yPos + 15);
      if (keyPressed) {
        blink = true;
        t = 0;
      }
    } else t = 0;

    fill(150);
    textSize(14);
    textAlign(RIGHT); 
    text(nfWithSpace(n, 3), 33, yPos + 15);
    textAlign(LEFT); 

    fill(255);
    textSize(14);
    text(text, 43, yPos + 15);
  }

  String nfWithSpace(int n_, int len) {
    String s = str(n_);
    s=trim(s);
    trim(s);
    if (s.length()==1) 
      return "  "+s;
    if (s.length()==2)
      return " "+s;
    // 
    return s;
  }

  int getn() {
    if (selected) return n;
    else return -1;
  }

  void mousePress() {
    if (selected &&
      rmbMenu.displayb == true && 
      mouseX > rmbMenu.x &&
      mouseX < rmbMenu.x + 160 &&
      mouseY > rmbMenu.y + 42 && 
      mouseY < rmbMenu.y + 58) {
      text = "";
    }

    if (! rmbMenu.displayb) {
      if (mouseButton == LEFT) {
        if (mouseY > 50 && 
          mouseY > yPos && 
          mouseY < yPos + 20 && 
          mouseX < 585)
          selected = true; 
        else if (mouseX < 585) selected = false;
      } else if (mouseButton == CENTER) {
        if (mouseY > 50 && 
          mouseY > yPos && 
          mouseY < yPos + 20 && 
          mouseX < 585) 
          selected = true;
      }
    }
  }

  void keyPress() {
    if (selected) {
      // eval key 
      if (key==BACKSPACE) {
        //BACKSPACE
        if (text.length()>0) {
          text=text.substring(0, text.length()-1);
        }
      } else if (key != CODED && textWidth(text) < 532) {
        // add Text 
        text+=key;
      }
      //
    }// if (selected == true) {
  }//method 

  void mouseDrag() {
    if (rmbMenu.displayb == false) {
      if (mouseButton == CENTER || mouseButton == LEFT) {
        if (sb.scroll == false &&
          mouseX < 585 && 
          mouseY > yPos &&
          mouseY < yPos + 20) {
          selected = true;
          blink = true;
        }
      }
    }
  }
}

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

class RMBMenu {

  int x = 0;
  int y = 0;

  boolean displayb = false;

  RMBMenu() {
  }

  void display() {
    if (displayb) {   
      stroke(150);
      fill(200);
      rect(x, y, 160, 60);

      line(x + 20, y + 2, x + 20, y + 58);

      //copy
      fill(0);
      textSize(14);
      text("Copy", x + 26, y + 15);

      noStroke();
      fill(0, 142, 237, 100);
      if (mouseX > x && mouseX < x + 160 && mouseY > y + 2 && mouseY < y + 18) rect(x, y + 2, 160, 16);

      //paste
      fill(0);
      textSize(14);
      text("Paste", x + 26, y + 35);

      noStroke();
      fill(0, 142, 237, 100);
      if (mouseX > x && mouseX < x + 160 && mouseY > y + 22 && mouseY < y + 38) rect(x, y + 22, 160, 16);

      //delete
      fill(0);
      textSize(14);
      text("Delete", x + 26, y + 55);

      noStroke();
      fill(0, 142, 237, 100);
      if (mouseX > x && mouseX < x + 160 && mouseY > y + 42 && mouseY < y + 158) rect(x, y + 42, 160, 16);
    }
  }

  void mousePress() {
    if (mouseX > x && mouseX < x + 160 && mouseY > y + 42 && mouseY < y + 58);

    if (mouseButton == RIGHT) {
      x = mouseX;
      y = mouseY;
      displayb = true;
    }

    if (mouseButton == LEFT) {
      if (displayb == true && mouseX > x && mouseY > y && mouseX < x + 160 && mouseY < y + 60) {
      } else displayb = false;
    }
  }
}

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

class Scrollbar {
  public int x;
  public int y;
  public int h;

  public int sy;
  public int sh;

  public color c = color(130);

  public boolean scroll = false;

  Scrollbar(int x1, int y1, int h1, int sh1) {
    x = x1;
    y = y1;
    h = h1;
    sy = y1 + 20;
    sh = sh1;
  }

  void display() {
    //base
    fill(200);
    noStroke();
    rect(x, y, 15, h);

    //up and down arrows
    fill(130);
    triangle(x + 3, y + 12, x + 12, y + 12, x + 8, y + 6);
    triangle(x + 3, y + h - 12, x + 12, y + h - 12, x + 8, y + h - 6);

    fill(160, 140);
    if (scroll == true || mouseX > x && mouseX < x + 15 && mouseY > y && mouseY < y + 20) rect(x, y, 15, 20);
    if (scroll == true || mouseX > x && mouseX < x + 15 && mouseY > y + h - 20 && mouseY < y + h) rect(x, y + h - 20, 15, 20);

    //scrollbar
    fill(c);
    noStroke();
    rect(x, sy, 15, sh);
    strokeWeight(1);
    stroke(80);
    line(x + 4, sy + sh/2 - 5, x + 11, sy + sh/2 - 5);
    line(x + 4, sy + sh/2, x + 11, sy + sh/2);
    line(x + 4, sy + sh/2 + 5, x + 11, sy + sh/2 + 5);

    if (mouseX > x && mouseX < x + 15 && mouseY > sy && mouseY < sy + sh || scroll == true) c = color(160);
    else c = color(130);
    if (scroll == true) {
      sy = mouseY - sh/2;
      scrolli = int(map(sy, 70, 220, 0, 30));
    }
    if (sy <= y + 20) sy = y + 20;
    if (sy + sh >= y + h - 20) sy = (y + h - 20) - sh;
  }

  void mouseScroll() {
  }

  void mousePress() {
    if (sy != y + 20 && mouseX > x && mouseX < x + 15 && mouseY > y && mouseY < y + 20) sy = sy - 20;
    if (sy != (y + h - 20) - sh && mouseX > x && mouseX < x + 15 && mouseY > y + h - 20 && mouseY < y + h) sy = sy + 20;

    if (mouseX > x && mouseX < x + 15 && mouseY > sy && mouseY < sy + sh ) {
      scroll = true;
    }
  }

  void mouseRelease() {
    scroll = false;
  }

  int getY() {
    return
      sy - 20;
  }

  float setScrollObjectY(int y1, int y2) {
    return
      -map(getY(), 
      y, (y + h) - (sh + 40), 
      y1, y2);
  }
}

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

class Toolbar {

  Toolbar() {
  }


  void display() {
    fill(theme2);
    noStroke();
    rect(0, 0, width, 50);

    stroke(theme1);
    strokeWeight(5);
    line(0, 41, width, 41);

    ////save button
    //image(save,10,7,25,25);

    ////open button
    //image(open,50,6,27,25);

    ////seperator1
    //stroke(130);
    //strokeWeight(1);
    //line(87,7,87,32);

    ////brush button
    //image(brush,97,6,27,27);
  }
}//class
//end
1 Like

Remark 8

to use LEFT and RIGHT cursor it is a neat trick, to split
the text of a line into two variables textLeft and textRight
(left and right from the cursor position in the line).

Then you have full control.

Just display them as textLeft + textRight.
When you leave the line say text=textLeft + textRight;

Let’s say, you move the cursor 3 letters left and

  • click backspace: textLeft loses one letter
  • click a letter: textLeft wins a letter
  • click delete: textRight loses a letter on the left side
  • click enter: insert a new line with textRight as the new text; delete textRight from the previous line
1 Like

Thanks so much! Really appreciate it.
I will try to do remark 8, it is pretty ingenious.
Thanks again for all the input and teaching me a bit of code cleaning in remarks 2, 3, 4, 5 and 6.

1 Like

You are welcome!

Despite Remark 3 your first line in the text editor can of course be labeled with 1. Or “car”.

Nothing to do with the for-loop.

1 Like

Hello,

I think youre almost as crazy as people who want to make their own OS :-).
I believe there are actually libraries out there that already provide text editing functionality.

But… if they forced me to do it myself, I would probably break things down to the smallest, inseparable unit: a character and create different classes.

A page class that covers all parameters for a page. The page class then has its own line class array.
There you handle line stuff. e.g. if the text in the line is too long, shove text to the next line.
Lines contain words -> e.g. to breaking words in two parts like “break- ing”
Words consist again of characters…

im not sure which would be the better direction. if you have a long string of text and break it down into characters, you can create “words” by assembling characters, then create lines by assembling words and so on.

that would make sense if you want to select a certain word or number of chars. -> the line object can detect your mouse positions and “collect” the appropriate words / characters and change their color to signify selection.

yet, again, to figure out sizes of lines, it seems to me that it would be interesting to fill a line with chars (including blanks). so that would be a top down creation, not vice versa.

maybe it could work if you have only two classes. a page and a char class.
the page class handles the positioning of the characters as well as selecting them, holding formatting information as well. it contains an array of all characters on that page and tells each of them if they are selected or not. or if some of them should be bold or normal style, and so on.

lines or words do not necessarily need to be a class of its own. the page class can store them in different lists, so when you want to do spell-checking you know which group of characters make a word…

the more I think of it - without testing - I think the last approach could indeed work well.

class Page () {
//------------------------------- variables
String fullText;
Character [] chars;
//------------------------------- constructor
Page () {
// create a character array with the size of all chars in the text
// fill them with each character
}
//------------------------------- methods
// stuff like detecting collision for selecting text
// create Lines and words
// do stuff like formatting or spell checking
// write stuff -> update the character collection (maybe using an ArrayList rather than an array - but I dislike ArrayLists :-))
}
class Character () {
// what's my format
// what's my position on screen
// am I selected
// what's my width and size
}
1 Like

heck of a post

but don’t confuse Word processor with Text Editor…

Haha, alright. That were just examples. Still selecting, pasting, deleting will be needed.
From that styling the text will not be too far away, no ?
:innocent:

1 Like

Libraries: look at controlp5 and c4p

@ everythingability
I don’t see the problem to do everything that exist already. The result will be of course different and can help other people. This editor is a blessing for me : I was stop on a similar project. I’m looking forward to try brastin OS (I’m on Linux).
There’s not only one way but different beautiful path. Anybody can find joy programming even if it’s different than mine.

4 Likes

I don’t really get this idea of “it already exist, no need to do it again”. If every inventor had this mindset, I don’t think we would have come this far with technology. But thanks for the input!

For @everythingability

I would personally argue that Processing is a tool for everyone, to make everything.

:D
1 Like

I also see it as a good practice to attack a problem.

By the way, maybe because of the font, I wasn’t able to see the menu.

I did a text input console once, must post

1 Like

Dont pout :slight_smile: There is nothing wrong with crazy deeds, quite the contrary. I absolutely agree that only those who disagree with the status quo will find new and maybe better ways to do something. One of the best examples - imho - the fact that women could not vote if they had not been against the established ways.

But you will forgive me that I just tried to point out that in the case of a text editor “simpler than notepad++” I wanted to save you some work…

Obviously your idea made me take time to think about your task. And I feel it was time well spent. But Im quite sure there are indeed problems that have been solved and that we can profit from other peoples work. Thats how scientific research works after all, no ?

2 Likes

I only said this because I know that with my current programming knowledge, I can’t make something like notepad++ :D

That is absolutely correct and I agree with it. I researched before asking this question and tried stuff. At first I was going to go with swings JTextArea but it didn’t fit my needs. So I decided to try and write my own code and when I needed help, I came here. It is actually kinda my fault I should have stated that I tried some libraries and they didn’t fit my needs.

1 Like

Simple text input console

Simple text input console, not a text editor.

I like that often help pops up in a small tetx box.

Use commands like:

  • Hello circle rect fill dump quit help show.
  • circle 110
  • fill 0 0 255
  • rect 110

Example Input:

rect
fill 0 0 255
circle

Warm regards,

Chrisir

Sketch:






// ********************************************************************************
//         joined pde-file of folder EditorSimple6
// ********************************************************************************


// ********************************************************************************
// tab: EditorSimple6.pde main file (file name is folder name)




// from https://discourse.processing.org/t/closed-user-types-codes-special-strings-if-correct-something-happends

// A Console.  
// The main program can send to console.
// Use commands like:: Hello circle rect fill dump quit help show. 
// Search for "Add your" here in the code to see where you can add more commands (3 major occurances with ****). 

// The main class 
Console console;

// texts 
MinorTexts minorTexts = new  MinorTexts();

// help text in yellow box
final String helpText = 
  "My little Console \n\n"
  +"Hit PgUp to toggle this help text.\n"
  +"Type text.\n"
  +"Hit enter to go to the next line.\n"
  +"Cursor up to copy previous line.\n"
  +"Use Backspace.\n"
  +"Try to type Hello and dump\n"
  +"Try circle 33 or circle x y r; circle help.\n"
  +"Try rect 33 or rect x y r; rect help.\n"
  +"Try fill/fill help and quit, show, clear.\n"
  +"Esc is disabled; use Alt-F4 instead.";

// help texts for cmds
final String strCircleHelp            = "circle can be used as: circle, circle radius, circle x y, circle x y r or circle x y w h. Example: circle 111.";
final String strRectHelp              = "rect can be used as: rect, rect radius, rect x y, rect x y r or rect x y w h. Example: rect 111.";
final String strFillHelp              = "fill can be used as: fill (just gives blue), fill GRAY-value (0..255), fill Red Green Blue. Example: fill 111.";
final String strQuestionMarkHelp      = "? can be used instead of help: ?fill or ?rect or ? circle"; 
final String strGeneralHelp1          = "Commands are help, quit, dump, show, fill, rect and circle.";
final String strGeneralHelp2          = "With some Commands, use ?rect etc. to get help for the command.";
final String strShowHelp              = "The command 'show' dumps only the internal list with your draw commands.";
final String strClearHelp             = "The command 'clear' clears the internal list with your draw commands.";

// list of commands
ListOfCommands listOfCommands = new ListOfCommands ();

// --------------------------------------------
// Processing Core Functions  

void setup() {
  size(660, 660);
  background(255);

  console = new Console(9, height-130, width-18, 125);
  //  console = new Console(9, height-330, 160, 310);

  console.send("Hello.");
}//setup()

void draw() {
  background(255);

  // show yellow box with help text 
  minorTexts.showHelpText();

  // parse list of commands - draws rects and circles...
  listOfCommands.parseList();

  // show console 
  console.showTextArrayConsole();

  // show error text in red 
  minorTexts.showErrorMessage(); 

  // show help message
  minorTexts.showHelpMessage();
}//draw()
//

// ********************************************************************************
// tab: classConsole.pde


// The core class 

class Console {

  // Pos of box
  float xBoxConsole, yBoxConsole;

  // writing pos inside box
  float xWriteConsole, yWriteConsole;

  // w and h 
  float wConsole, hConsole;

  // space between lines 
  int lineSpaceConsole=22; 

  //font
  PFont fontEditor; 

  // Editor variables 
  String[] lines = new String[300];
  int lineCounter1 = 0; // current line number 
  String lastLine="";      // after hitting Enter 
  String currentLine="";   // before hitting Enter

  // cursor sign blinks 
  boolean cursorBlinkFlag; 
  int timerCursorBlink;

  DateTimeTool dateTimeTool = new DateTimeTool(); 

  // constr 
  Console( float x_, float y_, 
    float w_, float h_) {

    xBoxConsole=x_;
    yBoxConsole=y_;

    xWriteConsole = xBoxConsole+3;
    yWriteConsole = yBoxConsole+20;

    wConsole=w_;
    hConsole=h_;

    fontEditor = createFont("ARIAL", 14);
    textFont(fontEditor); 
    lines[lineCounter1]="";
  }// constr   

  void showTextArrayConsole() {
    // The text field

    // box
    fill(190);     // gray
    stroke(0);     // Black
    rect(xBoxConsole, yBoxConsole, 
      wConsole, hConsole);

    // Text 
    fill(0); // black 
    // for loop 
    int start=lineCounter1- int((hConsole-25) / lineSpaceConsole);
    if (start<0)
      start=0; 
    int stop=lines.length; 
    int lineCounterForLoop=0;
    for (int i=start; i<stop+1; i++) {

      if ((lineCounterForLoop*lineSpaceConsole+yWriteConsole) > hConsole-10+yBoxConsole) {
        break;
      }

      if (lines[i]!=null) {

        text(lines[i], 
          xWriteConsole, lineCounterForLoop*lineSpaceConsole+yWriteConsole);

        showBlinkingCursor(lines[i], i, lineCounterForLoop);
      }//if
      lineCounterForLoop++;
    }//for
    //
  }//func

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

  boolean lastLineIs(String line_) {
    // equality 
    return lastLine.equals(line_);
  }// method

  boolean lastLineStartsWith(String line_) {
    // Is the param line_ present at start of last line? Rest of line is ignored
    return lastLine.indexOf(line_) == 0;
  }// method

  boolean isStringAtTheBeginningOfTheCurrentLine(String line_) {

    // This is checking if line_ (e.g. circle) is at the start of the line that is cuurently entered (console.currentLine)

    if (line_==null) 
      return false; 

    int lenLine = line_.length();
    lenLine = min(lenLine, currentLine.length());

    String compare1 = currentLine.substring(0, lenLine); 

    return line_.indexOf(compare1) == 0;
  }//func 

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

  void send(String line_) {
    lines[lineCounter1]=line_;
    lineCounter1++; // pitfall ???
    lines[lineCounter1]="";
  }//method

  boolean keyPressedConsole() {
    // eval key 
    // The return value is true for return or false for any other key. 
    boolean result=false; 
    if (key==CODED) {
      //CODED
      result=keyPressedConsoleForCodedKeys();
    } else {
      //not CODED
      result=keyPressedConsoleForNotCodedKeys();
    }
    //
    currentLine = lines[lineCounter1]; 
    return result; 
    //
  } // keyPressedConsole() 

  // ----

  boolean keyPressedConsoleForCodedKeys() {
    // Coded
    // CURSOR KEYS
    if (keyCode==UP) {
      // copy prev line
      if (lineCounter1>0) {
        lines[lineCounter1]=lines[lineCounter1-1];
      }
    } else if (keyCode==DOWN) {
      // ignore
    } else if (keyCode==LEFT) {
      // ignore
    } else if (keyCode==RIGHT) {
      // ignore
    }
    // IGNORE 
    else if (keyCode==ALT) {
      // ignore
    } else if (keyCode==CONTROL) {
      // ignore
    } else if (keyCode==SHIFT) {
      // ignore
    }   
    // IGNORE 
    else {
      // ignore
    } //else

    return false;
  }//func

  boolean keyPressedConsoleForNotCodedKeys() {
    // not Coded
    if ( keyCode == ENTER || keyCode == RETURN ) {
      // new line 
      lastLine=lines[lineCounter1]; 
      lineCounter1++; // pitfall ??? 
      lines[lineCounter1]="";
      currentLine=""; // (it's deleted below as well)
      return true;
    }//if 
    // Backspace and Escape keys
    else if (keyCode==BACKSPACE) {
      lines[lineCounter1] = shortenStringByOneSign(lines[lineCounter1]);
    } else if (key==ESC) {
      key=0; // kill ESC, stay in the program
    }
    // LETTERS - the usual input
    else if (keyCode>0||key=='?') {   // was: else if (keyCode>30||key=='?') {
      // normal text input 
      lines[lineCounter1] += key;
    } else {
      // ignore
    }//else 

    return false;
  }//func 

  // ----

  String shortenStringByOneSign( String strIn_) {
    if (strIn_.length()>0)
      return 
        strIn_.substring( 0, strIn_.length()-1 );
    else 
    return strIn_;
  }

  void showBlinkingCursor(String oneLine, int i, int lineCounterForLoop) {
    // manage and show the red Blinking Cursor |
    // Is it the current/active line?
    if (i==lineCounter1 && cursorBlinkFlag) {
      // show text cursor
      fill(255, 0, 0); // RED 
      text("|", 
        xWriteConsole + textWidth(oneLine), lineCounterForLoop*lineSpaceConsole+yWriteConsole);
      // back to normal
      fill(0);
    }//if

    // timer to toggle the flag cursorBlinkFlag
    if (millis()-timerCursorBlink > 330) {
      cursorBlinkFlag  = !cursorBlinkFlag; // toggle
      timerCursorBlink = millis();
    }//if
  }

  void dump() {
    // dump as file AND as println

    // For the file: get a date-time-stamp
    String dateTimeStampShort = dateTimeTool.dateTimeStampShort(); 
    // make a new array without null
    String[] newArray = arrayWithoutNull(lines); 
    // save array to file
    saveStrings( "result"+dateTimeStampShort+".txt", newArray);

    // Println array - this: printArray( newArray ); wouldn't work as good.  
    for (int i=0; i<newArray.length; i++) {
      println( newArray[i] );
    }//for
  }//method

  String[] arrayWithoutNull(String[] linesLocal) {
    String[] newArray = new String[0]; 
    for (int i=0; i<linesLocal.length; i++) {
      if (linesLocal[i]!=null) {
        newArray = append(newArray, linesLocal[i]);
      }//if
    }//for
    return newArray;
  }//method
  //
}//class
//

// ********************************************************************************
// tab: classDateTime.pde


// minor class to get a date-time-stamp from. 

class DateTimeTool {

  String dateTimeStampShort() {
    // short version 
    return getDate() + "_" + getTime();
  }

  String dateTimeStampLong() {
    // long version 
    return getDateLong()
      + " at " 
      + getTimeLong();
  }

  //-----

  String getTime() {
    return leadingZeros(hour()) 
      + leadingZeros(minute()) 
      + leadingZeros(second());
  }

  String getTimeLong() {
    return leadingZeros(hour()) 
      +":"+ leadingZeros(minute()) 
      +":"+ leadingZeros(second());
  }

  String getDate() {
    return leadingZeros(year()) 
      + leadingZeros(month()) 
      + leadingZeros(day());
  }

  String getDateLong() {
    return leadingZeros(year()) 
      +"/"+ leadingZeros(month()) 
      +"/"+ leadingZeros(day());
  }

  //-----

  String leadingZeros(int a) {
    String Buffer;
    Buffer=nf(a, 2);
    return(Buffer);
  }
  //
}//class
//

// ********************************************************************************
// tab: classListOfCommands.pde


// tab for the list of commands 

class ListOfCommands {

  ArrayList<String> listCmds = new ArrayList();

  void showCmdList() {
    // 
    for (String lineOfTheForLoop : listCmds) {
      println(lineOfTheForLoop);
    }//for

    String remark1="";
    if (listCmds.size()==0)
      remark1=" List is empty at the moment.";
    console.send("List of Commands are dumped in the processing console."
      +remark1);
  }//func 

  void parseList() {
    // parsing the cmd list 

    // *********************************************************************
    // Add your PERSISTENT commands here ***********************************
    // *********************************************************************

    fill(255, 0, 0);  // RED 

    for (String lineOfTheForLoop : listCmds) {

      // 1. circle command 
      if (lineOfTheForLoop.indexOf("circle")==0) {
        String line = lineOfTheForLoop.replace("circle", "");
        line = line.trim();
        // empty?
        if (line.equals("")) {
          // 0 params
          ellipse(width/2, height/2, 33, 33); // default circle
        }//if
        else {
          String[] params = split(line, " "); 
          // Different number of params:  
          if (params.length==3) 
            ellipse(float(params[0]), float(params[1]), float(params[2]), float(params[2]));
          else if (params.length==2) 
            ellipse(float(params[0]), float(params[1]), 33, 33);
          else if (params.length==1) 
            ellipse(width/2, height/2, float(params[0]), float(params[0]));
          else if (params.length==4) 
            ellipse(float(params[0]), float(params[1]), float(params[2]), float(params[3]));
          else {
            minorTexts.errMsg = "Circle command says unknown number of parameters("
              +params.length
              +"): " 
              + lineOfTheForLoop;
          }//else
        }//else
      }//if
      //
      // 2. rect command 
      else if (lineOfTheForLoop.indexOf("rect")==0) {
        String line = lineOfTheForLoop.replace("rect", "");
        line = line.trim();
        // empty?
        if (line.equals("")) {
          // 0 params
          rect(width/2, height/2, 33, 33); // default rect
        }//if
        else {
          String[] params = split(line, " "); 
          // Different number of params:  
          if (params.length==3) 
            rect(float(params[0]), float(params[1]), float(params[2]), float(params[2]));
          else if (params.length==2) 
            rect(float(params[0]), float(params[1]), 33, 33);
          else if (params.length==1) 
            rect(width/2, height/2, float(params[0]), float(params[0]));
          else if (params.length==4) 
            rect(float(params[0]), float(params[1]), float(params[2]), float(params[3]));
          else {
            minorTexts.errMsg = "rect command says unknown number of parameters("
              +params.length
              +"): " 
              + lineOfTheForLoop;
          }//else
        }//else
      }//else if
      //
      // 3. fill command 
      else if (lineOfTheForLoop.indexOf("fill")==0) {
        String line = lineOfTheForLoop.replace("fill", "");
        line = line.trim();
        // empty?
        if (line.equals("")) {
          // 0 params (also valid)
          fill(0, 0, 255); //  default : blue
        }//if
        else {
          String[] params = split(line, " "); 
          // Different number of params:  
          if (params.length==3) 
            fill(int(params[0]), int(params[1]), int(params[2])); // RGB 
          else if (params.length==1) 
            fill(float(params[0])); // GRAY 
          else {
            minorTexts.errMsg = "fill command says unknown number of parameters("
              +params.length
              +"): " 
              + lineOfTheForLoop;
          }//else
        }//else
      }//else if
      // 
      // add more commands here : triangle....
      // 
      else { 
        minorTexts.errMsg = "Unknown command in command list: "+lineOfTheForLoop;
      }//else 
      //
    }//for
    //
  }//func 
  //
}//class
//

// ********************************************************************************
// tab: classMinorTexts.pde


// Minor Tools: Text and messages 

class MinorTexts {

  // yellow box height
  final int heightYellowBox = 234; 

  // show the yellow box yes/ no (PgUp)
  boolean showYellowHelpBoxFlag = true; 

  // when we switch off the yellow box, this text is displayed  
  final String errMsgForShowYellowHelpBoxFlag = "Hit PgUp to toggle the yellow box help text.";

  // error 
  String errMsg="";

  // help 
  String helpMsg=""; 

  void showHelpText() {
    // Yellow box and text

    if (!showYellowHelpBoxFlag) { 
      return; // leave here
    }

    // Yellow box
    fill(#F6FA1C); // Yellow
    stroke(0);     // Black
    rect(width-225, 3, 
      210, heightYellowBox);

    // Black text
    fill(0); // Black
    textSize(12); 
    text(helpText, 
      width-220, 20);
    textSize(14);
  }

  void showErrorMessage() {
    // show error msg
    fill(255, 0, 0); // red
    text(errMsg, 
      console.xBoxConsole+10, console.yBoxConsole-23);
  }

  void showHelpMessage() {
    // show help msg in white

    // when there is no help msg, we leave here 
    if (helpMsg.equals(""))
      return;  // leave here 

    // The box for the help text
    float x = console.xBoxConsole+133; 
    float y = console.yBoxConsole-123; 
    float w = 224; 
    float h = 62;

    // for longer text we can make the box higher 
    if (helpMsg.length()>110) {
      h=82;
    }

    // draw 2 lines as a right angle
    stroke(0);
    // line left <- 
    line(x-1, y+h/2, 
      console.xBoxConsole+4, y+h/2);
    // line down |
    line(console.xBoxConsole+4, y+h/2, 
      console.xBoxConsole+4, console.yBoxConsole-4);

    // draw box
    noFill(); 
    fill(255); 
    rect(x, y, 
      w, h);

    // draw text
    fill( 0); //black
    text(helpMsg, 
      x+4, y+1, 
      w-2, h+10);
  }
  //
}//class
//

// ********************************************************************************
// tab: InputsKeyboard.pde


// Inputs Keyboard 

void keyPressed() {
  // eval key
  // println (keyCode);

  if (keyCode==33) {
    // PG Up
    evalPgUp();
  } //if
  else {
    // eval other keys
    sendKeyToConsole();  // see tab toolsInputs
  }//else
}//keyPressed() 

void evalPgUp() {
  // eval page up

  minorTexts.showYellowHelpBoxFlag = ! minorTexts.showYellowHelpBoxFlag;
  if (!minorTexts.showYellowHelpBoxFlag) {
    minorTexts.errMsg=minorTexts.errMsgForShowYellowHelpBoxFlag;
  }//if
  else {
    if (minorTexts.errMsg.equals(minorTexts.errMsgForShowYellowHelpBoxFlag))
      minorTexts.errMsg="";
  }//else
}
//

// ********************************************************************************
// tab: toolsInputs.pde


// Main Tools ; Inputs. 
// This tab takes inputs and communicates with the console class and executes commands, shows help for the commands during typing etc. 

void sendKeyToConsole() {
  // we send the key to the console.

  // The return value is true for RETURN or false for any other key. 
  if (console.keyPressedConsole()) {
    // return was pressed 
    // eval the last line
    evalTheLastLine();
  } else {
    // Any other key than return was pressed 
    // Show help during typing  
    evalTheCurrentLine();
  }//else
}//sendKeyToConsole() 

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

void evalTheLastLine() {
  // Evaluates the last line of the console (after ENTER has been pressed) 

  // reset 
  minorTexts.errMsg="";

  // Delete the help msg (reset) 
  minorTexts.helpMsg="";

  // *********************************************************************
  // Add your commands here **********************************************
  // *********************************************************************

  // We check the last line.
  // We use 
  //      * console.lastLineIs("Hello") for entire line check and 
  //      * console.lastLineStartsWith("circle ") for the beginning of a line (when parameters follow like in circle 120).  
  // 
  // The shorter a command is, the further back in the if..else if.. list it has to be ( console.lastLineStartsWith("circle help") BEFORE console.lastLineStartsWith("circle").
  // Commands like circle that draw on the screen need to be added to the listCmds:  listCmds.add(console.lastLine);   because background is used in draw() and deletes the canvas. 
  // You want to add your commands here and to parseList().
  // 
  if (console.lastLineIs("Hello")||console.lastLineIs("hello")) {
    // Hello 
    console.send("Hello to you, too");
  } else if (console.lastLineIs("show")) {
    // show
    listOfCommands.showCmdList();
  } else if (console.lastLineIs("box")) {
    // 
    console.send("Use rect instead of box please ");
  } else if (console.lastLineIs("clear")) {
    // show
    console.dump();
    listOfCommands.listCmds.clear();
    console.send("I dumped and cleared the draw commands list.");
  } else if (console.lastLineIs("dump")) {
    console.send("I dump the console. (dump as file AND as println)");
    console.dump();
  } else if (console.lastLineIs("help circle")||
    console.lastLineIs("circle help")||
    console.lastLineIs("circle?")||
    console.lastLineIs("?circle")||
    console.lastLineIs("circle ?")||
    console.lastLineIs("? circle")) {
    // we show help for circle 
    console.send(strCircleHelp);
  } else if (console.lastLineIs("help fill")||
    console.lastLineIs("fill help")||
    console.lastLineIs("fill?")||
    console.lastLineIs("?fill")||
    console.lastLineIs("fill ?")||
    console.lastLineIs("? fill")) {
    // we show help for fill 
    console.send(strFillHelp);
  } else if (console.lastLineIs("help rect")||
    console.lastLineIs("rect help")||
    console.lastLineIs("rect?")||
    console.lastLineIs("?rect")||
    console.lastLineIs("rect ?")||
    console.lastLineIs("? rect")) {
    // we show help for rect 
    console.send(strRectHelp);
  } else if (console.lastLineIs("help rect")||
    console.lastLineIs("? help")||
    console.lastLineIs("??")||
    console.lastLineIs("?")||
    console.lastLineIs("? ?")||
    console.lastLineIs("? ?")) {
    // we show help for ?
    console.send(strQuestionMarkHelp);
  }     
  //  
  else if (console.lastLineStartsWith("circle")) {
    // we add this to a list of commands 
    listOfCommands.listCmds.add(console.lastLine);
  }//
  else if (console.lastLineStartsWith("rect")) {
    // we add this to a list of commands 
    listOfCommands.listCmds.add(console.lastLine);
  }//
  else if (console.lastLineStartsWith("fill")) {
    // we add this to a list of commands 
    listOfCommands.listCmds.add(console.lastLine);
  }//
  else if (console.lastLineStartsWith("help")) {
    // 
    // we show help (2 lines) 
    console.send(strGeneralHelp1);
    console.send(strGeneralHelp2);
  }//
  else if (console.lastLineStartsWith("quit")) {
    // 
    console.send("I dump the console. (dump as file AND as println)");
    console.dump();
    exit();
  }//
  else {
    minorTexts.errMsg="Unknown command";
  }
}//evalTheLastLine() 

void evalTheCurrentLine() {
  // eval the line that is typed at the moment (before hitting Enter).
  // eval throughout (not only when Enter has been hit).
  // shows a help for the current word the user is typing. 

  // *********************************************************************
  // Add your help here **********************************************
  // *********************************************************************

  if (console.currentLine.equals("")) {
    minorTexts.helpMsg = "";//reset
  } else if (console.isStringAtTheBeginningOfTheCurrentLine("circle")) {
    minorTexts.helpMsg = strCircleHelp;
  } else if (console.isStringAtTheBeginningOfTheCurrentLine("fill")) {
    minorTexts.helpMsg = strFillHelp;
  } else if (console.isStringAtTheBeginningOfTheCurrentLine("rect")) {
    minorTexts.helpMsg = strRectHelp;
  } else if (console.isStringAtTheBeginningOfTheCurrentLine("show")) {
    minorTexts.helpMsg = strShowHelp;
  } else if (console.isStringAtTheBeginningOfTheCurrentLine("clear")) {
    minorTexts.helpMsg = strClearHelp;
  } else if (console.isStringAtTheBeginningOfTheCurrentLine("help")) {
    // 2 lines 
    minorTexts.helpMsg = strGeneralHelp1
      +"\n"
      +strGeneralHelp2;
  } else if ("?".indexOf(console.currentLine) == 0) {
    minorTexts.helpMsg = strQuestionMarkHelp;
  } 
  // ---
  else {
    minorTexts.helpMsg = ""; // reset
  }//else
}//func 
//

// End of joined file. ********************************************************************************



1 Like

Hi, I made a small new version of you editor with less of computer ressources.
I create a “selectLine” variable to not use a for loop in keyPressed function.
Now ENTER and BACKSPACE touch works.

PFont font;

PImage save;
PImage open;
PImage brush;

color theme1 = color(0, 8, 48);
color theme2 = color(0, 7, 30);

boolean bluet = true;
boolean darkt = false;

int scrolli = 0;
int selectLine = 0;
float scrolli2;

Line l1 = new Line(40, 1);
Toolbar t = new Toolbar();
Scrollbar sb = new Scrollbar(585, 50, 350, 60);
RMBMenu r = new RMBMenu();

ArrayList<Line> lines;

void setup() {
    size(600, 400);
    surface.setTitle("EpicTextEditor v0.1");
    font = loadFont("TeXGyreAdventor-Bold-48.vlw");
    textFont(font);
    //save = loadImage("saveIcon.png");
    //open = loadImage("openIcon.png");
    //brush = loadImage("brushIcon2.png");
    lines = new ArrayList<Line>();
    for (int i = 0; i < 50; i++) {
        lines.add(new Line(i * 20 + 30, i));
    }
}

void draw() {
    background(theme1);
    //themes
    if (darkt) {
        theme1 = color(70);
        theme2 = color(30);
    }
    for (int i = 0; i < 50; i++) {
        Line l = lines.get(i);
        l.y = sb.setScrollObjectY(0, 650) + (i * 20 + 30);
    }
    for (int i = 0; i < 50; i++) {
        Line l = lines.get(i);
        l.display();
    }
    t.display();
    sb.display();
    r.display();
}

void mousePressed() {
    sb.mousePress();
    r.mousePress();

    for (int i = 0; i < 50; i++) {
        Line l = lines.get(i);
        l.mousePress();
    }
}

void mouseReleased() {
    sb.mouseRelease();
}

void keyPressed() {
    lines.get(selectLine).keyPress();
}

void mouseDragged() {
    for (int i = 0; i < 50; i++) {
        Line l = lines.get(i);
        l.mouseDrag();
    }
}

void mouseWheel(MouseEvent event) {
    scrolli = constrain(scrolli + event.getCount(), 0, 50);
    scrolli2 = map(scrolli, 0, 30, 70, 220);
    sb.sy = int(scrolli2);
}

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

class Line {

    String text = "";

    boolean selected;

    float yCtrl;
    float y;
    int n;

    boolean blink = true;
    int t = 0;

    Line(float y1, int n1) {
        y = y1;
        n = n1;
    }


    void display() {
        fill(theme1);
        noStroke();
        rect(0, y, width, 20);

        fill(theme2);
        rect(0, y, 40, 20);

        if (selected == true) {
            fill(0, 110);
            rect(0, y, width, 20);

            //blinking line
            fill(255);
            textSize(14);
            t++;
            if (t > 30) {
                blink = !blink;
                t = 0;
            }
            if (blink == true) text("|", 43 + textWidth(text), y + 15);
            if (keyPressed) {
                blink = true;
                t = 0;
            }
        } else t = 0;

        fill(150);
        textSize(14);
        text(nf(n, 3), 7, y + 15);

        fill(255);
        textSize(14);
        text(text, 43, y + 15);
    }
    void selectOn() {
        selected = true;
        selectLine = n;
    }
    int getn() {
        if (selected == true) return n;
        else return -1;
    }

    void mousePress() {
        if (selectLine == n && r.displayb == true && mouseX > r.x && mouseX < r.x + 160 && mouseY > r.y + 42 && mouseY < r.y + 58) text = "";

        if (r.displayb == false) {
            if (mouseButton == LEFT) {
                if (mouseY > 50 && mouseY > y && mouseY < y + 20 && mouseX < 585) selectOn(); 
                else if (mouseX < 585) selected = false;
            } else if (mouseButton == CENTER) {
                if (mouseY > 50 && mouseY > y && mouseY < y + 20 && mouseX < 585) selectOn();
            }
        }
    }
    void keyPress() {
        if (selectLine == n) {   
            if ((key==ENTER || keyCode==DOWN) && n<49) {
                selected = false;
                lines.get(selectLine+1).selectOn();
            } else if (key==BACKSPACE) {
                if (text.length()>0) {
                    text=text.substring(0, text.length()-1);
                } else if(n>1) {
                    selected = false;
                    lines.get(selectLine-1).selectOn();
                }
            } else if (key != CODED && textWidth(text) < 532) {
                text+=key;
            }
        }
    }

    void mouseDrag() {
        if (r.displayb == false) {
            if (mouseButton == CENTER || mouseButton == LEFT) {
                if (sb.scroll == false && mouseX < 585 && mouseY > y && mouseY < y + 20) {
                    selectOn();
                    blink = true;
                }
            }
        }
    }
}

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

class RMBMenu {

    int x = 0;
    int y = 0;

    boolean displayb = false;

    RMBMenu() {
    }

    void display() {
        if (displayb == true) {   
            stroke(150);
            fill(200);
            rect(x, y, 160, 60);

            line(x + 20, y + 2, x + 20, y + 58);

            //copy
            fill(0);
            textSize(14);
            text("Copy", x + 26, y + 15);

            noStroke();
            fill(0, 142, 237, 100);
            if (mouseX > x && mouseX < x + 160 && mouseY > y + 2 && mouseY < y + 18) rect(x, y + 2, 160, 16);

            //paste
            fill(0);
            textSize(14);
            text("Paste", x + 26, y + 35);

            noStroke();
            fill(0, 142, 237, 100);
            if (mouseX > x && mouseX < x + 160 && mouseY > y + 22 && mouseY < y + 38) rect(x, y + 22, 160, 16);

            //delete
            fill(0);
            textSize(14);
            text("Delete", x + 26, y + 55);

            noStroke();
            fill(0, 142, 237, 100);
            if (mouseX > x && mouseX < x + 160 && mouseY > y + 42 && mouseY < y + 158) rect(x, y + 42, 160, 16);
        }
    }

    void mousePress() {
        if (mouseX > x && mouseX < x + 160 && mouseY > y + 42 && mouseY < y + 58);

        if (mouseButton == RIGHT) {
            x = mouseX;
            y = mouseY;
            displayb = true;
        }

        if (mouseButton == LEFT) {
            if (displayb == true && mouseX > x && mouseY > y && mouseX < x + 160 && mouseY < y + 60) {
            } else displayb = false;
        }
    }
}

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

class Scrollbar {
    public int x;
    public int y;
    public int h;

    public int sy;
    public int sh;

    public color c = color(130);

    public boolean scroll = false;

    Scrollbar(int x1, int y1, int h1, int sh1) {
        x = x1;
        y = y1;
        h = h1;
        sy = y1 + 20;
        sh = sh1;
    }

    void display() {
        //base
        fill(200);
        noStroke();
        rect(x, y, 15, h);

        //up and down arrows
        fill(130);
        triangle(x + 3, y + 12, x + 12, y + 12, x + 8, y + 6);
        triangle(x + 3, y + h - 12, x + 12, y + h - 12, x + 8, y + h - 6);

        fill(160, 140);
        if (scroll == true || mouseX > x && mouseX < x + 15 && mouseY > y && mouseY < y + 20) rect(x, y, 15, 20);
        if (scroll == true || mouseX > x && mouseX < x + 15 && mouseY > y + h - 20 && mouseY < y + h) rect(x, y + h - 20, 15, 20);

        //scrollbar
        fill(c);
        noStroke();
        rect(x, sy, 15, sh);
        strokeWeight(1);
        stroke(80);
        line(x + 4, sy + sh/2 - 5, x + 11, sy + sh/2 - 5);
        line(x + 4, sy + sh/2, x + 11, sy + sh/2);
        line(x + 4, sy + sh/2 + 5, x + 11, sy + sh/2 + 5);

        if (mouseX > x && mouseX < x + 15 && mouseY > sy && mouseY < sy + sh || scroll == true) c = color(160);
        else c = color(130);
        if (scroll == true) {
            sy = mouseY - sh/2;
            scrolli = int(map(sy, 70, 220, 0, 30));
        }
        if (sy <= y + 20) sy = y + 20;
        if (sy + sh >= y + h - 20) sy = (y + h - 20) - sh;
    }

    void mouseScroll() {
    }

    void mousePress() {
        if (sy != y + 20 && mouseX > x && mouseX < x + 15 && mouseY > y && mouseY < y + 20) sy = sy - 20;
        if (sy != (y + h - 20) - sh && mouseX > x && mouseX < x + 15 && mouseY > y + h - 20 && mouseY < y + h) sy = sy + 20;

        if (mouseX > x && mouseX < x + 15 && mouseY > sy && mouseY < sy + sh ) {
            scroll = true;
        }
    }

    void mouseRelease() {
        scroll = false;
    }

    int getY() {
        return(sy - 20);
    }

    float setScrollObjectY(int y1, int y2) {
        return(-map(getY(), y, (y + h) - (sh + 40), y1, y2));
    }
}

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

class Toolbar {

    Toolbar() {
    }


    void display() {
        fill(theme2);
        noStroke();
        rect(0, 0, width, 50);

        stroke(theme1);
        strokeWeight(5);
        line(0, 41, width, 41);

        ////save button
        //image(save,10,7,25,25);

        ////open button
        //image(open,50,6,27,25);

        ////seperator1
        //stroke(130);
        //strokeWeight(1);
        //line(87,7,87,32);

        ////brush button
        //image(brush,97,6,27,27);
    }
}

//end

to @ qewer3322 ---- I would like to use your code to create an alternative free, easy-to-use and basic of powerpoint with Processing. Do you agree ?

1 Like

I don’t think my code is very good for that but you absolutely can!
Oh are you going to make pages like lines?

1 Like

I will try to use your text editor over the pictures of the powerpoint page.
Now any pages has his own text written in a external editor.
With your code I can do everything in the same environment, it’s what I dream and now I can. Thanks !
When it will be finish I will share it with the community, let’s see …

2 Likes

You can actually use g4p’s textarea instead of my code it would probably work much better!

:D
1 Like