Loading...
Logo
Processing Forum

Hello,

this is probably simple but I couldn't find it on the forum.

I did a flowchart and you can click the single items and drag them.

This is done in the class with checking if mouseX and mouseY are within the item
and when it is the item returns mouseOver == true and can be dragged. Works fine.
Line 406/407 are bold.

But when I scale or translate the whole graphic (right mouse button drag)
the items wander on the screen but mouseX and mouseY don't.

So the checking if mouseX and mouseY are within the item doesn't work anymore.

I tried to multiply the mouseX and mouseY with my var myScale but didn't work.

What is the formula please to check if mouseX and mouseY are within the item?

Thank you so much!


Greetings, Chrisir  



Copy code
  1. // this prgram provides a flowchart / diagram
  2. // http://en.wikipedia.org/wiki/Flowchart
  3. ArrayList<GraphicalItem> graphicalItems;
  4. //
  5. final color lightGreen = color (2, 244, 2, 22);
  6. final color lightBlue = color(2, 0, 244, 22);
  7. // State of program
  8. final int stateNormal = 0;
  9. int state=stateNormal;
  10. //
  11. // for graphical:
  12. final int typeOfGraphicalItemStandardWithHeader = 0;
  13. final int typeOfGraphicalItemStandardWithoutHeader = 1;
  14. final int typeOfGraphicalItemConditional = 2;
  15. final int typeOfGraphicalItemStartEnd = 3;
  16. //
  17. // for graphical: which adaptor is used on a box?
  18. // (clockwise) north, east, south or west.
  19. final int adaptorNorth=0;
  20. final int adaptorEast=1;
  21. final int adaptorSouth=2;
  22. final int adaptorWest=3;
  23. //
  24. // for scale and translating
  25. float myScale = 1.0;     
  26. float myTranslate = 0.0;  // only y-direction
  27. // where to place next box vertically
  28. int lineY = 40;
  29. //
  30. // for drag and drop:
  31. // mouse dragged?
  32. boolean hold=false;   
  33. GraphicalItem holdItem ;  // which item is dragged
  34. // for drag and drop: difference between the upper left corner
  35. // x,y position and where mouse clicked in the graphical item
  36. PVector offSet;
  37. // ---------------------------------------------------------------
  38. void setup() {
  39.   // size( screen.width, screen.height );
  40.   size( 800, 600 );
  41.   smooth();
  42.   noStroke();
  43.   fill(0);
  44.   offSet=new PVector();
  45.   // Create an empty ArrayList
  46.   graphicalItems = new ArrayList();
  47.   // fill the ArrayList
  48.   initGraphical() ;
  49. } // func
  50. //
  51. //
  52. void draw() {
  53.   background(255);
  54.   //
  55.   if (state==stateNormal) {
  56.     scale(myScale);
  57.     translate( 0, myTranslate ) ;    
  58.     showGraphical();
  59.   }
  60.   else {
  61.     println ("Error 182" );
  62.   }
  63. } // func
  64. //
  65. //
  66. // =================================================================
  67. // Init items
  68. void initGraphical() {
  69.   // fills the graphicalItems in the arrayList
  70.   graphicalItems.clear();
  71.   lineY = 40;
  72.   //
  73.   graphicalItems.add ( new GraphicalItem(
  74.   typeOfGraphicalItemStandardWithHeader, 20, lineY,
  75.   "Entry 0", "This is interesting",
  76.   null,
  77.   lightGreen ));
  78.   int EntryGreen =  graphicalItems.size()-1;
  79.   graphicalItems.add ( new GraphicalItem(
  80.   typeOfGraphicalItemStandardWithHeader, 320, lineY,
  81.   "Entry 1", "This is lightblue ",
  82.   new AdaptorType(EntryGreen, adaptorWest, adaptorEast),
  83.   lightBlue ));
  84.   int EntryBlue =  graphicalItems.size()-1; 
  85.   graphicalItems.add ( new GraphicalItem(
  86.   typeOfGraphicalItemConditional,
  87.   100, lineY+100,
  88.   "", "Conditional",
  89.   new AdaptorType(EntryGreen, adaptorNorth, adaptorSouth),
  90.   color (0) ));
  91.   int EntryConditional =  graphicalItems.size()-1; 
  92.   lineY+=70;
  93.   graphicalItems.add ( new GraphicalItem(
  94.   typeOfGraphicalItemStartEnd,
  95.   180, lineY+100,
  96.   "", "Test2",
  97.   new AdaptorType(EntryConditional, adaptorNorth, adaptorEast),
  98.   color (0) ));
  99.   lineY+=70;
  100.   graphicalItems.add ( new GraphicalItem(
  101.   typeOfGraphicalItemStartEnd,
  102.   40, lineY+100,
  103.   "", "Test3",
  104.   new AdaptorType(EntryConditional, adaptorNorth, adaptorWest),
  105.   color (0) ));
  106.   int EntryStartItem = graphicalItems.size()-1;
  107.   graphicalItems.add ( new GraphicalItem(
  108.   typeOfGraphicalItemStandardWithoutHeader,
  109.   240, lineY+200,
  110.   "", "Test3",
  111.   new AdaptorType(EntryBlue, adaptorNorth, adaptorSouth),
  112.   color (0) ));
  113.   //
  114.   // add further Line to last item. This line
  115.   // goes from the last item (it's west side) to item
  116.   // number EntryStartItem (south)
  117.   AddLineToElement( graphicalItems.size()-1,
  118.   EntryStartItem,
  119.   adaptorWest,
  120.   adaptorSouth );
  121.   //
  122. } // func
  123. //
  124. // Inputs ****************************************************
  125. //
  126. void mousePressed() {
  127.   if (state==stateNormal) {
  128.     if (mouseButton==LEFT) {
  129.       for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  130.         GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  131.         if (myGraphicalItem1.isMouseOver()) {
  132.           hold     = true;
  133.           holdItem = myGraphicalItem1;
  134.           offSet.x= myGraphicalItem1.Position.x-mouseX;
  135.           offSet.y= myGraphicalItem1.Position.y-mouseY;
  136.         }
  137.       } // for
  138.     } // if
  139.   } // if
  140. } // func
  141. //
  142. void mouseDragged() {
  143.   if (state==stateNormal) {
  144.     if (hold) {
  145.       holdItem.Position.x = mouseX+offSet.x;
  146.       holdItem.Position.y = mouseY+offSet.y;
  147.     }
  148.     if (mousePressed && mouseButton == RIGHT) {
  149.       myScale = map(mouseX, 0, width, 0, 2); 
  150.       myTranslate = map(mouseY, 0, height, -height, height);
  151.     } // if
  152.   } // if
  153. } // func
  154. //
  155. void mouseReleased () {
  156.   if (state==stateNormal) {
  157.     if (mouseButton == LEFT) {
  158.       hold = false;
  159.     }
  160.   }
  161. } // function
  162. //
  163. void keyPressed () {
  164.   if (state==stateNormal) {
  165.     //
  166.     if (key=='r') {
  167.       myScale = 1.0;     
  168.       myTranslate = 0.0;
  169.     }
  170.   }
  171.   else {
  172.     println("Error 429: unknown state ");
  173.   }
  174. } // keyPressed
  175. //-----------------------------------------------------------
  176. //
  177. void AddLineToElement( int NumberOfStartItem, int NumberOfTargetItem,
  178. int adaptor1, int adaptor2) {
  179.   // add a line
  180.   GraphicalItem itemStart = graphicalItems.get(NumberOfStartItem);
  181.   itemStart.addAdaptor ( new AdaptorType(NumberOfTargetItem, adaptor1, adaptor2) );
  182. }
  183. //
  184. void showGraphical() {
  185.   // show the graphicalItems from the arrayList
  186.   textAlign(LEFT);
  187.   text ( "Graphical Representation"
  188.     + " - "
  189.     + "Move items with left Mouse button. Drag with right mouse button: scale "
  190.     + "(x-direction) and up/down (y-direction).", 20, 14 );
  191.   if (graphicalItems.isEmpty()) {
  192.     text("Graphical Diagram is empty.", 220, 170 );
  193.   }
  194.   else
  195.   {
  196.     for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  197.       GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  198.       myGraphicalItem1.display() ;
  199.     } // for
  200.   } // if else
  201. } // func
  202. //
  203. GraphicalItem getElement( String textHeaderParam, String textNormalParam ) {
  204.   // returns object or null
  205.   for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  206.     GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  207.     if (myGraphicalItem1.textHeader.equals(textHeaderParam) &&
  208.       myGraphicalItem1.textNormal.equals(textNormalParam)) {
  209.       return myGraphicalItem1;
  210.     } // if
  211.   } // for
  212.   return null;
  213. } // func
  214. //
  215. int getElementNumber( String textHeaderParam, String textNormalParam ) {
  216.   // returns number of object or -1
  217.   for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  218.     GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  219.     if (myGraphicalItem1.textHeader.equals(textHeaderParam) &&
  220.       myGraphicalItem1.textNormal.equals(textNormalParam)) {
  221.       return i;
  222.     } // if
  223.   } // for
  224.   return -1;
  225. } // func
  226. //
  227. // ==============================================================
  228. class GraphicalItem {
  229.   //
  230.   PVector Position;   // Pos and size of the whole box
  231.   PVector boxSize;    // Size
  232.   final int headerHeight = 20;  // Height of header text box
  233.   color headerColor;   //  color of header box
  234.   // the type of the item
  235.   int typeOfGraphicalItem;
  236.   // texts
  237.   String textHeader="";
  238.   String textNormal="";
  239.   // Positions of adaptors
  240.   PVector adaptorLeft, adaptorRight;
  241.   PVector adaptorUp, adaptorDown; 
  242.   //
  243.   // where the adaptors lead to: array of
  244.   // AdaptorType (see class AdaptorType)
  245.   AdaptorType adaptorTo[] = new AdaptorType [1]  ; 
  246.   //
  247.   //
  248.   // constructor ----------
  249.   GraphicalItem(
  250.   int _typeOfGraphicalItem,
  251.   int _x, int _y,
  252.   String _header, String _normalText,
  253.   AdaptorType _adaptorTo,
  254.   color _tempColor) {
  255.     //
  256.     // constructor
  257.     Position = new PVector( _x, _y);
  258.     boxSize  = new PVector( 100, 70 );
  259.     textHeader    = _header;
  260.     textNormal    = _normalText;
  261.     adaptorTo [0] = _adaptorTo;
  262.     //
  263.     typeOfGraphicalItem=_typeOfGraphicalItem;
  264.     //
  265.     if (typeOfGraphicalItem == typeOfGraphicalItemConditional) {
  266.       // Conditional item = ttiangle
  267.       // calculate the four adaptors pos
  268.       adaptorUp = new PVector( boxSize.x/2, 0 );
  269.       adaptorRight = new PVector( 2*boxSize.x/3+11, boxSize.y/2 );   
  270.       // adaptorDown  = new PVector( boxSize.x/2, boxSize.y );
  271.       adaptorLeft = new PVector( boxSize.x/3-7, boxSize.y/2 );
  272.     }
  273.     else {
  274.       // calculate the four adaptors pos
  275.       adaptorUp = new PVector( boxSize.x/2, 0 );
  276.       adaptorRight = new PVector( boxSize.x, boxSize.y/2 );   
  277.       adaptorDown  = new PVector( boxSize.x/2, boxSize.y );
  278.       adaptorLeft = new PVector( 0, boxSize.y/2 );
  279.     }
  280.     //
  281.     headerColor = _tempColor;
  282.     plausibilityCheck();
  283.   }// constructor
  284.   //
  285.   void plausibilityCheck () {
  286.     // checks whether there are not plausible parameters, e.g.
  287.     // a defined header with a typeOfGraphicalItem that has no
  288.     // header.
  289.     if (typeOfGraphicalItem == typeOfGraphicalItemConditional ||
  290.       typeOfGraphicalItem == typeOfGraphicalItemStandardWithoutHeader ||
  291.       typeOfGraphicalItem == typeOfGraphicalItemStartEnd  ) {
  292.       if (!textHeader.trim().equals("")) {
  293.         println("Remark 285: StandardWithoutHeader or Conditional etc. has defined header (not shown) with header: '"
  294.           + textHeader
  295.           + "' and normal text: '"
  296.           + textNormal
  297.           + "'. "
  298.           + "Type being: "
  299.           + typeOfGraphicalItem
  300.           + ". Header ignored.");
  301.       }
  302.     }
  303.   }
  304.   //
  305.   void display() {
  306.     switch (typeOfGraphicalItem) {
  307.     case typeOfGraphicalItemStandardWithHeader:
  308.       displayStandardWithHeader() ;
  309.       break;
  310.     case typeOfGraphicalItemStandardWithoutHeader:
  311.       displayStandardWithoutHeader();
  312.       break;
  313.     case typeOfGraphicalItemConditional:
  314.       displayConditional();
  315.       break;
  316.     case typeOfGraphicalItemStartEnd:
  317.       displayStartEnd();
  318.       break;
  319.     default:
  320.       println("Error occured 245");
  321.       break;
  322.     } // switch
  323.     //
  324.   } // method
  325.   //
  326.   void displayStandardWithHeader() {
  327.     fill (headerColor);
  328.     stroke(0);
  329.     // header rect
  330.     rect (Position.x, Position.y,
  331.     boxSize.x, headerHeight);
  332.     fill(244);
  333.     // rect for normal text field (lower half)
  334.     rect (Position.x, Position.y+headerHeight,
  335.     boxSize.x, boxSize.y-headerHeight);   
  336.     fill (0);
  337.     text (textHeader, Position.x+4, Position.y+2, boxSize.x-5, headerHeight);
  338.     text (textNormal, Position.x+4, Position.y+headerHeight+2, boxSize.x-5, boxSize.y-headerHeight);
  339.     // adaptors --------
  340.     for (int i=0; i < adaptorTo.length; i++) {
  341.       if (adaptorTo[i] != null) {
  342.         adaptorTo[i].display ( this ) ;
  343.       } // if
  344.     } // for
  345.   } // method
  346.   //
  347.   void displayStandardWithoutHeader() {
  348.     fill(244);
  349.     // rect for text field
  350.     rect (Position.x, Position.y,
  351.     boxSize.x, boxSize.y);   
  352.     fill (0);
  353.     text (textNormal, Position.x+4, Position.y+2, boxSize.x-5, boxSize.y);
  354.     // adaptors --------
  355.     for (int i=0; i < adaptorTo.length; i++) {
  356.       if (adaptorTo[i] != null) {
  357.         adaptorTo[i].display ( this ) ;
  358.       } // if
  359.     } // for
  360.   } // method
  361.   //
  362.   void displayConditional() {
  363.     // Conditional is triangle
  364.     fill(244);
  365.     triangle (Position.x, Position.y,
  366.     Position.x+boxSize.x+0, Position.y,
  367.     Position.x+boxSize.x/2+5, Position.y + boxSize.y);   
  368.     fill (0);
  369.     textAlign(CENTER);
  370.     text (textNormal,
  371.     Position.x+2, Position.y+2,
  372.     boxSize.x-5, boxSize.y );
  373.     // adaptors ----------
  374.     for (int i=0; i < adaptorTo.length; i++) {
  375.       if (adaptorTo[i] != null) {
  376.         adaptorTo[i].display ( this ) ;
  377.       } // if
  378.     } // for
  379.   } // method
  380.   //
  381.   void displayStartEnd() {
  382.     fill(244);
  383.     ellipseMode(CORNER);
  384.     ellipse (Position.x, Position.y, boxSize.x, boxSize.y);   
  385.     fill (0);
  386.     textAlign(CENTER);
  387.     text (textNormal,
  388.     Position.x+7, Position.y+18,
  389.     boxSize.x-5, boxSize.y );
  390.     // adaptors ------------
  391.     for (int i=0; i < adaptorTo.length; i++) {
  392.       if (adaptorTo[i] != null) {
  393.         adaptorTo[i].display ( this ) ;
  394.       } // if
  395.     } // for
  396.   } // method
  397.   //
  398.   void addAdaptor(AdaptorType _adaptorTo) {
  399.     // appends one line on a existing GraphicalItem
  400.     if (_adaptorTo.adaptorToGraphicalItem > -1) {
  401.       adaptorTo = (AdaptorType[])append( adaptorTo, _adaptorTo );
  402.     }
  403.   } // method
  404.   //
  405.   boolean isMouseOver() {
  406.     if (mouseX*1>Position.x && mouseX*1<Position.x+boxSize.x &&
  407.       mouseY*1>Position.y && mouseY*1<Position.y+boxSize.y) {
  408.       return true;
  409.     }
  410.     else
  411.     {
  412.       return false;
  413.     }
  414.   } // method
  415.   //
  416.   boolean isMouseOver_OLD() {
  417.     if (mouseX>Position.x && mouseX<Position.x+boxSize.x &&
  418.       mouseY>Position.y && mouseY<Position.y+boxSize.y) {
  419.       return true;
  420.     }
  421.     else
  422.     {
  423.       return false;
  424.     }
  425.   } // method
  426. } // class
  427. // ==============================================================
  428. class AdaptorType {
  429.   // Represents one connecting line.
  430.   //
  431.   // Start point (FROM) is a point at
  432.   // the GraphicalItem (a box) this
  433.   // AdaptorType-object belongs to.
  434.   // End point (TO) is another GraphicalItem
  435.   // marked by the var adaptorToGraphicalItem
  436.   // which is an Index for the ArrayList
  437.   // graphicalItems.
  438.   // To specify the exakt point at
  439.   // the from-GraphicalItem, the var
  440.   // fromAdaptor denotes whether it's
  441.   // (clockwise) north, east, south or west.
  442.   // And: To specify the exakt point at
  443.   // the to-GraphicalItem, the var
  444.   // toAdaptor denotes whether it's
  445.   // (clockwise) north, east, south or west.
  446.   //
  447.   // Indices of another GraphicalItem
  448.   int adaptorToGraphicalItem  = -1;    // other graphical item
  449.   // from which Adaptor of the four
  450.   int fromAdaptor = 1;   // 0 = north adaptor, 1 = east adaptor, 2 = south adaptor, 3 = west adaptor
  451.   // to which Adaptor of the four 
  452.   int toAdaptor   = 1;   // 0 = north adaptor, 1 = east adaptor, 2 = south adaptor, 3 = west adaptor
  453.   //
  454.   AdaptorType (int tempAdaptorToGraphicalItem,
  455.   int tempFromAdaptor,
  456.   int tempToAdaptor ) {
  457.     adaptorToGraphicalItem = tempAdaptorToGraphicalItem;
  458.     fromAdaptor = tempFromAdaptor;
  459.     toAdaptor = tempToAdaptor;
  460.   } //
  461.   //
  462.   void display(GraphicalItem startGraphicalItem) {
  463.     if (adaptorToGraphicalItem > -1) {
  464.       PVector startVector = getPVector
  465.         (startGraphicalItem,
  466.       fromAdaptor);
  467.       PVector endVector = getPVector
  468.         ( (GraphicalItem) graphicalItems.get( adaptorToGraphicalItem),
  469.       toAdaptor);      
  470.       //
  471.       line ( startVector.x, startVector.y,
  472.       endVector.x, endVector.y );
  473.     } // if
  474.   } // method
  475.   PVector getPVector(GraphicalItem startGraphicalItem, int whichAdaptor) {
  476.     PVector buffer = new PVector ();
  477.     //
  478.     switch (whichAdaptor) {
  479.     case adaptorNorth:
  480.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorUp.x;
  481.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorUp.y;
  482.       break;
  483.     case adaptorEast:
  484.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorRight.x;
  485.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorRight.y;
  486.       break;
  487.     case adaptorSouth:
  488.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorDown.x;
  489.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorDown.y;
  490.       break;
  491.     case adaptorWest:
  492.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorLeft.x;
  493.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorLeft.y;
  494.       break;
  495.     default:
  496.       println ("Error 337");
  497.       break;
  498.     } // switch
  499.     return buffer;
  500.   } // method
  501. } // class
  502. // ==============================================================

Replies(7)

You can replace your isMouseOver() function by the following:
Copy code
  1.   boolean isMouseOver() {
  2.     if (mouseX/myScale > Position.x
  3.      && mouseX/myScale < Position.x + boxSize.x
  4.      && mouseY/myScale - myTranslate > Position.y
  5.      && mouseY/myScale - myTranslate < Position.y + boxSize.y) {
  6.       return true;
  7.     } else {
  8.       return false;
  9.     }
  10.   }
That's the mouseOver. There are probably some other functions (like the dragging distance) that are also affected by the scale. So you could correct those for scale as well.

Something else. You are actually using an isOverRect() function as a general isMouseOver. But you have non-rect shapes as well. So another improvement would be to have isOverCircle() and isOverTriangle() functions as well. In that sense it would probably make more sense to have a general Shape object and several subclasses that extend the main Shape such as rectangle, triangle and circle. Each with their custom isMouseOver() function (same name, but different functionality).

hello,

I have another question.

I have to connect two graphical items with a line (or two lines go from one item to two others).

At the moment the line is a simple class AdaptorType depending from the class GraphicalItem.

But the target GraphicalItem where the line leads to is referred by it's index in the ArrayList (that's done in class AdaptorType, I made the lines bold, see below).

That sounds very unwise since when you remove one item, all indices after it change, right?

So it's unstable / not reliable.

What is the alternative?

Is it possible to make a pointer (direct reference?) to the object itself which would stay the same after removing another?

To do so, could the constructor return this reference?
See line 79ff. where I use the index at the moment.

Thank you!

Greetings, Chrisir      



Copy code
  1. // this prgram provides a flowchart / diagram
  2. // http://en.wikipedia.org/wiki/Flowchart
  3. ArrayList<GraphicalItem> graphicalItems;
  4. //
  5. final color lightGreen = color (2, 244, 2, 22);
  6. final color lightBlue = color(2, 0, 244, 22);
  7. // State of program
  8. final int stateNormal = 0;
  9. int state=stateNormal;
  10. //
  11. // for graphical:
  12. final int typeOfGraphicalItemStandardWithHeader = 0;
  13. final int typeOfGraphicalItemStandardWithoutHeader = 1;
  14. final int typeOfGraphicalItemConditional = 2;
  15. final int typeOfGraphicalItemStartEnd = 3;
  16. //
  17. // for graphical: which adaptor is used on a box?
  18. // (clockwise) north, east, south or west.
  19. final int adaptorNorth=0;
  20. final int adaptorEast=1;
  21. final int adaptorSouth=2;
  22. final int adaptorWest=3;
  23. //
  24. // for scale and translating
  25. float myScale = 1.0;     
  26. float myTranslate = 0.0;  // only y-direction
  27. // where to place next box vertically
  28. int lineY = 40;
  29. //
  30. // for drag and drop:
  31. // mouse dragged?
  32. boolean hold=false;   
  33. GraphicalItem holdItem ;  // which item is dragged
  34. // for drag and drop: difference between the upper left corner
  35. // x,y position and where mouse clicked in the graphical item
  36. PVector offSet;
  37. // ---------------------------------------------------------------
  38. void setup() {
  39.   // size( screen.width, screen.height );
  40.   size( 800, 600 );
  41.   smooth();
  42.   noStroke();
  43.   fill(0);
  44.   offSet=new PVector();
  45.   // Create an empty ArrayList
  46.   graphicalItems = new ArrayList();
  47.   // fill the ArrayList
  48.   initGraphical() ;
  49. } // func
  50. //
  51. //
  52. void draw() {
  53.   background(255);
  54.   //
  55.   if (state==stateNormal) {
  56.     scale(myScale);
  57.     translate( 0, myTranslate ) ;    
  58.     showGraphical();
  59.   }
  60.   else {
  61.     println ("Error 182" );
  62.   }
  63. } // func
  64. //
  65. //
  66. // =================================================================
  67. // Init items
  68. void initGraphical() {
  69.   // fills the graphicalItems in the arrayList
  70.   graphicalItems.clear();
  71.   lineY = 40;
  72.   //
  73.   graphicalItems.add ( new GraphicalItem(
  74.   typeOfGraphicalItemStandardWithHeader, 20, lineY,
  75.   "Entry 0", "This is interesting",
  76.   null,
  77.   lightGreen ));

  78.   int EntryGreen =  graphicalItems.size()-1;

  79.   graphicalItems.add ( new GraphicalItem(
  80.   typeOfGraphicalItemStandardWithHeader, 320, lineY,
  81.   "Entry 1", "This is lightblue ",
  82.   new AdaptorType(EntryGreen, adaptorWest, adaptorEast),
  83.   lightBlue ));

  84.   int EntryBlue =  graphicalItems.size()-1; 
  85.   graphicalItems.add ( new GraphicalItem(
  86.   typeOfGraphicalItemConditional,
  87.   100, lineY+100,
  88.   "", "Conditional",
  89.   new AdaptorType(EntryGreen, adaptorNorth, adaptorSouth),
  90.   color (0) ));
  91.   int EntryConditional =  graphicalItems.size()-1; 
  92.   lineY+=70;
  93.   graphicalItems.add ( new GraphicalItem(
  94.   typeOfGraphicalItemStartEnd,
  95.   180, lineY+100,
  96.   "", "Test2",
  97.   new AdaptorType(EntryConditional, adaptorNorth, adaptorEast),
  98.   color (0) ));
  99.   lineY+=70;
  100.   graphicalItems.add ( new GraphicalItem(
  101.   typeOfGraphicalItemStartEnd,
  102.   40, lineY+100,
  103.   "", "Test3",
  104.   new AdaptorType(EntryConditional, adaptorNorth, adaptorWest),
  105.   color (0) ));
  106.   int EntryStartItem = graphicalItems.size()-1;
  107.   graphicalItems.add ( new GraphicalItem(
  108.   typeOfGraphicalItemStandardWithoutHeader,
  109.   240, lineY+200,
  110.   "", "Test3",
  111.   new AdaptorType(EntryBlue, adaptorNorth, adaptorSouth),
  112.   color (0) ));
  113.   //
  114.   // add further Line to last item. This line
  115.   // goes from the last item (it's west side) to item
  116.   // number EntryStartItem (south)
  117.   AddLineToElement( graphicalItems.size()-1,
  118.   EntryStartItem,
  119.   adaptorWest,
  120.   adaptorSouth );
  121.   //
  122. } // func
  123. //
  124. // Inputs ****************************************************
  125. //
  126. void mousePressed() {
  127.   if (state==stateNormal) {
  128.     if (mouseButton==LEFT) {
  129.       // drag one item
  130.       for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  131.         GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  132.         if (myGraphicalItem1.isMouseOver()) {
  133.           hold     = true;
  134.           holdItem = myGraphicalItem1;
  135.           offSet.x = myGraphicalItem1.Position.x-mouseX;
  136.           offSet.y = myGraphicalItem1.Position.y-mouseY;
  137.         }
  138.       } // for
  139.     } // if
  140.   } // if
  141. } // func
  142. //
  143. void mouseDragged() {
  144.   if (state==stateNormal) {
  145.     if (hold) {
  146.       // mouseButton is LEFT
  147.       holdItem.Position.x = mouseX+offSet.x;
  148.       holdItem.Position.y = mouseY+offSet.y;
  149.     }
  150.     else if (mousePressed && (mouseButton == RIGHT)) {
  151.       myScale = map(mouseX, 0, width, 0, 2); 
  152.       myTranslate = map(mouseY, 0, height, -height, height);
  153.     } // if
  154.   } // if
  155. } // func
  156. //
  157. void mouseReleased () {
  158.   if (state==stateNormal) {
  159.     if (mouseButton == LEFT) {
  160.       hold = false;
  161.       println("f");
  162.     }
  163.   }
  164. } // function
  165. //
  166. void keyPressed () {
  167.   if (state==stateNormal) {
  168.     //
  169.     if (key=='r') {
  170.       // reset scale and translate
  171.       myScale = 1.0;     
  172.       myTranslate = 0.0;
  173.     }
  174.     else
  175.     {
  176.       // do nothing
  177.     }
  178.   }
  179.   else {
  180.     println("Error 429: unknown state ");
  181.   }
  182. } // keyPressed
  183. //-----------------------------------------------------------
  184. //
  185. void AddLineToElement( int NumberOfStartItem, int NumberOfTargetItem,
  186. int adaptor1, int adaptor2) {
  187.   // add a line
  188.   GraphicalItem itemStart = graphicalItems.get(NumberOfStartItem);
  189.   itemStart.addAdaptor ( new AdaptorType(NumberOfTargetItem, adaptor1, adaptor2) );
  190. }
  191. //
  192. void showGraphical() {
  193.   // show the graphicalItems from the arrayList
  194.   textAlign(LEFT);
  195.   text ( "Graphical Representation"
  196.     + " - "
  197.     + "Move items with left Mouse button. Drag with right mouse button: scale "
  198.     + "(x-direction) and up/down (y-direction).", 20, 14 );
  199.   if (graphicalItems.isEmpty()) {
  200.     text("Graphical Diagram is empty.", 220, 170 );
  201.   }
  202.   else
  203.   {
  204.     for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  205.       GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  206.       myGraphicalItem1.display() ;
  207.     } // for
  208.   } // if else
  209. } // func
  210. //
  211. GraphicalItem getElement( String textHeaderParam, String textNormalParam ) {
  212.   // returns object or null
  213.   for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  214.     GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  215.     if (myGraphicalItem1.textHeader.equals(textHeaderParam) &&
  216.       myGraphicalItem1.textNormal.equals(textNormalParam)) {
  217.       return myGraphicalItem1;
  218.     } // if
  219.   } // for
  220.   return null;
  221. } // func
  222. //
  223. int getElementNumber( String textHeaderParam, String textNormalParam ) {
  224.   // returns number of object or -1
  225.   for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  226.     GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  227.     if (myGraphicalItem1.textHeader.equals(textHeaderParam) &&
  228.       myGraphicalItem1.textNormal.equals(textNormalParam)) {
  229.       return i;
  230.     } // if
  231.   } // for
  232.   return -1;
  233. } // func
  234. //
  235. // ==============================================================
  236. class GraphicalItem {
  237.   //
  238.   PVector Position;   // Pos and size of the whole box
  239.   PVector boxSize;    // Size
  240.   final int headerHeight = 20;  // Height of header text box
  241.   color headerColor;   //  color of header box
  242.   // the type of the item
  243.   int typeOfGraphicalItem;
  244.   // texts
  245.   String textHeader="";
  246.   String textNormal="";
  247.   //
  248.   // where the adaptors lead to: array of
  249.   // AdaptorType (see class AdaptorType)
  250.   AdaptorType adaptorTo[] = new AdaptorType [1]; 
  251.   //
  252.   // Positions of adaptors
  253.   PVector adaptorLeft, adaptorRight;
  254.   PVector adaptorUp, adaptorDown;
  255.   //
  256.   // constructor ----------
  257.   GraphicalItem(
  258.   int _typeOfGraphicalItem,
  259.   int _x, int _y,
  260.   String _header, String _normalText,
  261.   AdaptorType _adaptorTo,
  262.   color _tempColor) {
  263.     //
  264.     // constructor
  265.     Position = new PVector( _x, _y);
  266.     boxSize  = new PVector( 100, 70 );
  267.     textHeader    = _header;
  268.     textNormal    = _normalText;
  269.     adaptorTo [0] = _adaptorTo;
  270.     //
  271.     typeOfGraphicalItem=_typeOfGraphicalItem;
  272.     //
  273.     if (typeOfGraphicalItem == typeOfGraphicalItemConditional) {
  274.       // Conditional item = ttiangle
  275.       // calculate the four adaptors pos
  276.       adaptorUp = new PVector( boxSize.x/2, 0 );
  277.       adaptorRight = new PVector( 2*boxSize.x/3+11, boxSize.y/2 );   
  278.       // adaptorDown  = new PVector( boxSize.x/2, boxSize.y );
  279.       adaptorLeft = new PVector( boxSize.x/3-7, boxSize.y/2 );
  280.     }
  281.     else {
  282.       // calculate the four adaptors pos
  283.       adaptorUp = new PVector( boxSize.x/2, 0 );
  284.       adaptorRight = new PVector( boxSize.x, boxSize.y/2 );   
  285.       adaptorDown  = new PVector( boxSize.x/2, boxSize.y );
  286.       adaptorLeft = new PVector( 0, boxSize.y/2 );
  287.     }
  288.     //
  289.     headerColor = _tempColor;
  290.     plausibilityCheck();
  291.   }// constructor
  292.   //
  293.   void plausibilityCheck () {
  294.     // checks whether there are not plausible parameters, e.g.
  295.     // a defined header with a typeOfGraphicalItem that has no
  296.     // header.
  297.     if (typeOfGraphicalItem == typeOfGraphicalItemConditional ||
  298.       typeOfGraphicalItem == typeOfGraphicalItemStandardWithoutHeader ||
  299.       typeOfGraphicalItem == typeOfGraphicalItemStartEnd  ) {
  300.       if (!textHeader.trim().equals("")) {
  301.         println("Remark 285: StandardWithoutHeader or Conditional etc. has defined header (not shown) with header: '"
  302.           + textHeader
  303.           + "' and normal text: '"
  304.           + textNormal
  305.           + "'. "
  306.           + "Type being: "
  307.           + typeOfGraphicalItem
  308.           + ". Header ignored.");
  309.       }
  310.     }
  311.   }
  312.   //
  313.   void display() {
  314.     switch (typeOfGraphicalItem) {
  315.     case typeOfGraphicalItemStandardWithHeader:
  316.       displayStandardWithHeader() ;
  317.       break;
  318.     case typeOfGraphicalItemStandardWithoutHeader:
  319.       displayStandardWithoutHeader();
  320.       break;
  321.     case typeOfGraphicalItemConditional:
  322.       displayConditional();
  323.       break;
  324.     case typeOfGraphicalItemStartEnd:
  325.       displayStartEnd();
  326.       break;
  327.     default:
  328.       println("Error occured 245");
  329.       break;
  330.     } // switch
  331.     //
  332.   } // method
  333.   //
  334.   void displayStandardWithHeader() {
  335.     fill (headerColor);
  336.     stroke(0);
  337.     // header rect
  338.     rect (Position.x, Position.y,
  339.     boxSize.x, headerHeight);
  340.     fill(244);
  341.     // rect for normal text field (lower half)
  342.     rect (Position.x, Position.y+headerHeight,
  343.     boxSize.x, boxSize.y-headerHeight);   
  344.     fill (0);
  345.     text (textHeader, Position.x+4, Position.y+2, boxSize.x-5, headerHeight);
  346.     text (textNormal, Position.x+4, Position.y+headerHeight+2, boxSize.x-5, boxSize.y-headerHeight);
  347.     // adaptors --------
  348.     for (int i=0; i < adaptorTo.length; i++) {
  349.       if (adaptorTo[i] != null) {
  350.         adaptorTo[i].display ( this ) ;
  351.       } // if
  352.     } // for
  353.   } // method
  354.   //
  355.   void displayStandardWithoutHeader() {
  356.     fill(244);
  357.     // rect for text field
  358.     rect (Position.x, Position.y,
  359.     boxSize.x, boxSize.y);   
  360.     fill (0);
  361.     text (textNormal, Position.x+4, Position.y+2, boxSize.x-5, boxSize.y);
  362.     // adaptors --------
  363.     for (int i=0; i < adaptorTo.length; i++) {
  364.       if (adaptorTo[i] != null) {
  365.         adaptorTo[i].display ( this ) ;
  366.       } // if
  367.     } // for
  368.   } // method
  369.   //
  370.   void displayConditional() {
  371.     // Conditional is triangle
  372.     fill(244);
  373.     triangle (Position.x, Position.y,
  374.     Position.x+boxSize.x+0, Position.y,
  375.     Position.x+boxSize.x/2+5, Position.y + boxSize.y);   
  376.     fill (0);
  377.     textAlign(CENTER);
  378.     text (textNormal,
  379.     Position.x+2, Position.y+2,
  380.     boxSize.x-5, boxSize.y );
  381.     // adaptors ----------
  382.     for (int i=0; i < adaptorTo.length; i++) {
  383.       if (adaptorTo[i] != null) {
  384.         adaptorTo[i].display ( this ) ;
  385.       } // if
  386.     } // for
  387.   } // method
  388.   //
  389.   void displayStartEnd() {
  390.     fill(244);
  391.     ellipseMode(CORNER);
  392.     ellipse (Position.x, Position.y, boxSize.x, boxSize.y);   
  393.     fill (0);
  394.     textAlign(CENTER);
  395.     text (textNormal,
  396.     Position.x+7, Position.y+18,
  397.     boxSize.x-5, boxSize.y );
  398.     // adaptors ------------
  399.     for (int i=0; i < adaptorTo.length; i++) {
  400.       if (adaptorTo[i] != null) {
  401.         adaptorTo[i].display ( this ) ;
  402.       } // if
  403.     } // for
  404.   } // method
  405.   //
  406.   void addAdaptor(AdaptorType _adaptorTo) {
  407.     // appends one line on a existing GraphicalItem
  408.     if (_adaptorTo.adaptorToGraphicalItem > -1) {
  409.       adaptorTo = (AdaptorType[])append( adaptorTo, _adaptorTo );
  410.     }
  411.   } // method
  412.   //
  413.   boolean isMouseOver() {
  414.     if (mouseX/myScale > Position.x
  415.       && mouseX/myScale < Position.x + boxSize.x
  416.       && mouseY/myScale - myTranslate > Position.y
  417.       && mouseY/myScale - myTranslate < Position.y + boxSize.y) {
  418.       return true;
  419.     } // if
  420.     else {
  421.       return false;
  422.     } // if else
  423.   } // method
  424.   //
  425. } // class
  426. // ==============================================================
  427. class AdaptorType {
  428.   // Represents one connecting line.
  429.   //
  430.   // Start point (FROM) is a point at
  431.   // the GraphicalItem (a box) this
  432.   // AdaptorType-object belongs to.
  433.   // End point (TO) is another GraphicalItem
  434.   // marked by the var adaptorToGraphicalItem
  435.   // which is an Index for the ArrayList
  436.   // graphicalItems.
  437.   // To specify the exakt point at
  438.   // the from-GraphicalItem, the var
  439.   // fromAdaptor denotes whether it's
  440.   // (clockwise) north, east, south or west.
  441.   // And: To specify the exakt point at
  442.   // the to-GraphicalItem, the var
  443.   // toAdaptor denotes whether it's
  444.   // (clockwise) north, east, south or west.
  445.   //
  446.   // Indices of another GraphicalItem
  447.   int adaptorToGraphicalItem  = -1;    // other graphical item
  448.   // from which Adaptor of the four
  449.   int fromAdaptor = 1;   // 0 = north adaptor, 1 = east adaptor, 2 = south adaptor, 3 = west adaptor
  450.   // to which Adaptor of the four 
  451.   int toAdaptor   = 1;   // 0 = north adaptor, 1 = east adaptor, 2 = south adaptor, 3 = west adaptor
  452.   //
  453.   AdaptorType (int tempAdaptorToGraphicalItem,
  454.   int tempFromAdaptor,
  455.   int tempToAdaptor ) {
  456.     adaptorToGraphicalItem = tempAdaptorToGraphicalItem;
  457.     fromAdaptor = tempFromAdaptor;
  458.     toAdaptor = tempToAdaptor;
  459.   } //
  460.   //
  461.   void display(GraphicalItem startGraphicalItem) {
  462.     if (adaptorToGraphicalItem > -1) {
  463.       PVector startVector = getPVector
  464.         (startGraphicalItem, fromAdaptor);
  465.       PVector endVector = getPVector
  466.         ((GraphicalItem) graphicalItems.get(adaptorToGraphicalItem), toAdaptor);      
  467.       //
  468.       line ( startVector.x, startVector.y,
  469.       endVector.x, endVector.y );
  470.     } // if
  471.   } // method
  472.   //
  473.   PVector getPVector(GraphicalItem startGraphicalItem, int whichAdaptor) {
  474.     PVector buffer = new PVector ();
  475.     //
  476.     switch (whichAdaptor) {
  477.     case adaptorNorth:
  478.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorUp.x;
  479.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorUp.y;
  480.       break;
  481.     case adaptorEast:
  482.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorRight.x;
  483.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorRight.y;
  484.       break;
  485.     case adaptorSouth:
  486.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorDown.x;
  487.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorDown.y;
  488.       break;
  489.     case adaptorWest:
  490.       buffer.x=startGraphicalItem.Position.x+startGraphicalItem.adaptorLeft.x;
  491.       buffer.y=startGraphicalItem.Position.y+startGraphicalItem.adaptorLeft.y;
  492.       break;
  493.     default:
  494.       println ("Error 337 - unknown adaptor");
  495.       break;
  496.     } // switch
  497.     return buffer;
  498.   } // method
  499. } // class
  500. // ==============================================================

There are always more ways than one to do it. In all cases you will have to deal with adding/removing/displaying objects and adding/removing/displaying connections.

You could use direct references to the connected objects. But remember that as long as an object is referenced it 'stays in existence', meaning that removing the 'original object' reference from the arraylist will not remove the connection nor the object from memory.

You could give each object a uniqueID. Once each object has a reliable ID you can use it in different ways. You could store and display the connections at the object or the global level. Either way uniqueID's are useful for keeping track of connections etc.

Put something like this at the global level:
Copy code
  1. int id;
  2. int getUniqueID() {
  3.   return id++;
  4. }

Then put something like this in your objects.
Copy code
  1. class SomeObject {
  2.       int objectID; // holds the object's unique ID

  3.       SomeObject() {
  4.         objectID = getUniqueID();
  5.       }
  6.      
  7.       getObjectID() {
  8.             return objectID;
  9.       }
  10. }
Without analyzing deeply your code (a bit long...), I can answer 'yes' to your question: don't pass around indexes, it is indeed very brittle. Just pass the objects themselves, you will pass actually just references to these objects.
Don't do x.add(new Item()) but do Item item = new Item(); x.add(item); so you can pass the item to the next constructor.
Note 1: the cast on graphicalItems.get() isn't necessary (old habit? You omit it elsewhere).
Note 2: for (int i = 0; i <= graphicalItems.size()-1; i++) is more usually written for (int i = 0; i < graphicalItems.size(); i++). For a trained eye, the first form makes the mind to pause and think, while the second one is just glanced at once.
Note 3: When you don't need an index, the new for loop is handy:
Copy code
  1.     for (int i=0; i < adaptorTo.length; i++) {
  2.       if (adaptorTo[i] != null) {
  3.         adaptorTo[i].display ( this ) ;
  4.       } // if
  5.     } // for
can be:
Copy code
  1.     for (AdaptorType to : adaptorTo) {
  2.       if (to != null) {
  3.         to.display ( this ) ;
  4.       } // if
  5.     } // for
(why you don't use an array list here?)
or:
Copy code
  1.   for (int i = 0; i <= graphicalItems.size()-1; i++ ) {
  2.     GraphicalItem myGraphicalItem1 = graphicalItems.get(i);
  3.     if (myGraphicalItem1.textHeader.equals(textHeaderParam) &&
  4.       myGraphicalItem1.textNormal.equals(textNormalParam)) {
  5.       return myGraphicalItem1;
  6.     } // if
  7.   } // for
can be:
Copy code
  1.   for (GraphicalItem myGraphicalItem : graphicalItems) {
  2.     if (myGraphicalItem.textHeader.equals(textHeaderParam) &&
  3.         myGraphicalItem.textNormal.equals(textNormalParam)) {
  4.       return myGraphicalItem;
  5.     } // if
  6.   } // for
Minor superficial remarks...
I haven't tried yet this sketch, but from the screen shot, it looks impressive.


that's very helpful!

Thank you both!

And thanks for the word "impressive" 


Hello,

I now did what you both told me...

You can drag the items with left mouse,
scale (x and y) and translate (only y) with right mouse (r resets).
When item is selected it is marked with a * and you can remove it by delete.
n = new diagram
u = un-select

It works with an unique ID now.

Works fine.

Thanks again!

Greetings, Chrisir


Copy code
  1. // this program provides a flowchart / diagram
  2. // http://en.wikipedia.org/wiki/Flowchart
  3. ArrayList<GraphicalItem> graphicalItems;
  4. //
  5. // State of program
  6. final int stateNormal = 0;
  7. int state=stateNormal;
  8. //
  9. // for graphical:
  10. final int typeOfGraphicalItemStandardWithHeader = 0;
  11. final int typeOfGraphicalItemStandardWithoutHeader = 1;
  12. final int typeOfGraphicalItemConditional = 2;
  13. final int typeOfGraphicalItemStartEnd = 3;
  14. // to be able to name those types we use an array
  15. // which order of indices must be according to the consts
  16. // above:
  17. final String[] typeOfGraphicalItemName = {
  18.   "Box with header",
  19.   "Box without header",
  20.   "Condition",
  21.   "Start or End"
  22. };
  23. //
  24. // for graphical: which adaptor is used on a box?
  25. // (clockwise) north, east, south or west.
  26. final int adaptorNorth=0;
  27. final int adaptorEast=1;
  28. final int adaptorSouth=2;
  29. final int adaptorWest=3;
  30. //
  31. // colors
  32. final color lightGreen = color (2, 244, 2, 22);
  33. final color lightBlue = color(2, 0, 244, 22);
  34. final color black = color (0);
  35. //
  36. // for scale and translating
  37. float myScale = 1.0;     
  38. float myTranslate = 0.0;  // only y-direction
  39. //
  40. // for drag and drop:
  41. // mouse dragged?
  42. boolean hold=false;   
  43. GraphicalItem holdItem ;  // which item is dragged
  44. // for drag and drop: difference between the upper left corner
  45. // x,y position and where mouse clicked in the graphical item
  46. PVector offSet=new PVector();
  47. //
  48. // for unique ID
  49. int id=1000;
  50. // which item is selected
  51. int selected = -1;
  52. //
  53. // Main functions ****************************************************
  54. //
  55. void setup() {
  56.   // size( screen.width, screen.height );
  57.   size( 800, 600 );
  58.   println("start of the program");
  59.   // smooth();
  60.   noStroke();
  61.   fill(0);
  62.   // Create an empty ArrayList
  63.   graphicalItems = new ArrayList();
  64.   // fill the ArrayList
  65.   initGraphical();
  66.   println("end of setup()");
  67. } // func
  68. //
  69. //
  70. void draw() {
  71.   background(255);
  72.   // depending on program's state
  73.   if (state == stateNormal) {
  74.     scale(myScale);
  75.     translate( 0, myTranslate ) ;    
  76.     showGraphical();
  77.   }
  78.   else {
  79.     println ("Error 182 - unknown state" );
  80.   }
  81. } // func
  82. //
  83. // Init diagram ****************************************************
  84. //
  85. void initGraphical() {
  86.   // Init items:
  87.   // fill the graphicalItems in the arrayList.
  88.   //
  89.   // where to place next box vertically
  90.   int lineY = 40;  
  91.   // clear list  
  92.   graphicalItems.clear();
  93.   //
  94.   // item to be defined
  95.   GraphicalItem item;
  96.   //
  97.   item = new GraphicalItem(
  98.   typeOfGraphicalItemStandardWithHeader, 20, lineY,
  99.   "Entry 0", "This is interesting",
  100.   null,
  101.   lightGreen );
  102.   graphicalItems.add (item);
  103.   int EntryGreen = item.objectID;
  104.   item=new GraphicalItem(
  105.   typeOfGraphicalItemStandardWithHeader, 320, lineY,
  106.   "Entry 1", "This is lightblue ",
  107.   new AdaptorType(EntryGreen, adaptorWest, adaptorEast),
  108.   lightBlue );
  109.   graphicalItems.add ( item );
  110.   int EntryBlue = item.objectID;
  111.   item=new GraphicalItem(
  112.   typeOfGraphicalItemConditional,
  113.   100, lineY+100,
  114.   "", "Conditional",
  115.   new AdaptorType(EntryGreen, adaptorNorth, adaptorSouth),
  116.   color (0) );
  117.   graphicalItems.add (item);
  118.   int EntryConditional = item.objectID;
  119.   lineY+=70;
  120.   item=new GraphicalItem(
  121.   typeOfGraphicalItemStartEnd,
  122.   180, lineY+100,
  123.   "", "Test 2",
  124.   new AdaptorType(EntryConditional, adaptorNorth, adaptorEast),
  125.   color (0) );
  126.   graphicalItems.add (item);
  127.   lineY+=70;
  128.   item= new GraphicalItem(
  129.   typeOfGraphicalItemStartEnd,
  130.   40, lineY+100,
  131.   "", "Test3",
  132.   new AdaptorType(EntryConditional, adaptorNorth, adaptorWest),
  133.   color (0) );
  134.   graphicalItems.add (item);
  135.   int EntryStartItem = item.objectID;
  136.   item= new GraphicalItem(
  137.   typeOfGraphicalItemStandardWithoutHeader,
  138.   240, lineY+200,
  139.   "", "Test3",
  140.   new AdaptorType(EntryBlue, adaptorNorth, adaptorSouth),
  141.   color (0) );
  142.   graphicalItems.add (item);
  143.   int WithoutHeaderItem = item.objectID;
  144.   //
  145.   // add further Line to item WithoutHeaderItem. This line
  146.   // goes from the last item (it's west side) to item
  147.   // number EntryStartItem (south side)
  148.   AddLineToElement( WithoutHeaderItem,
  149.   EntryStartItem,
  150.   adaptorWest,
  151.   adaptorSouth );
  152.   //
  153. } // func
  154. //
  155. // Inputs ****************************************************
  156. //
  157. void mousePressed() {
  158.   if (state==stateNormal) {
  159.     if (mouseButton==LEFT) {
  160.       // drag one item
  161.       for (GraphicalItem myGraphicalItem : graphicalItems) {       
  162.         if (myGraphicalItem.isMouseOver()) {
  163.           selected = myGraphicalItem.getObjectID();
  164.           hold     = true;
  165.           holdItem = myGraphicalItem;
  166.           offSet.x = myGraphicalItem.Position.x-mouseX;
  167.           offSet.y = myGraphicalItem.Position.y-mouseY;
  168.         } // if
  169.       } // for
  170.     } // if
  171.   } // if
  172. } // func
  173. //
  174. void mouseDragged() {
  175.   if (state==stateNormal) {
  176.     if (hold) {
  177.       // mouseButton is LEFT
  178.       holdItem.Position.x = mouseX+offSet.x;
  179.       holdItem.Position.y = mouseY+offSet.y;
  180.     }
  181.     else if (mousePressed && (mouseButton == RIGHT)) {
  182.       myScale = map(mouseX, 0, width, 0, 2); 
  183.       myTranslate = map(mouseY, 0, height, -height, height);
  184.     } // if
  185.   } // if
  186. } // func
  187. //
  188. void mouseReleased () {
  189.   if (state==stateNormal) {
  190.     if (mouseButton == LEFT) {
  191.       hold = false;
  192.     }
  193.   }
  194. } // function
  195. //
  196. void keyPressed () {
  197.   if (state==stateNormal) {
  198.     keyPressedStateNormal();
  199.   }
  200.   else {
  201.     println("Error 429: unknown state ");
  202.   }
  203. } // keyPressed
  204. //
  205. void keyPressedStateNormal() {
  206.   // eval keys for state normal
  207.   if (!(key==CODED)) {
  208.     if (key=='r') {
  209.       // reset scale and translate
  210.       myScale = 1.0;     
  211.       myTranslate = 0.0;
  212.     } // the r
  213.     else if (key=='n') {
  214.       // make new diagram
  215.       println ("new diagram ----");
  216.       initGraphical();
  217.     } // the n
  218.     else if (key=='u') { // un-mark
  219.       // remove marker
  220.       selected=-1;
  221.     } // the u
  222.     else if (key==DELETE) {
  223.       // delete selected item.
  224.       // if there are items:
  225.       if (!graphicalItems.isEmpty()) {
  226.         //get selected
  227.         GraphicalItem itemSelected = getElementByID(selected);
  228.         if (itemSelected!=null) {
  229.           // delete it
  230.           itemSelected.delete();
  231.           // remove marker
  232.           selected=-1;
  233.         }
  234.         else
  235.         {
  236.           println ("Delete: Found no selected item. Select with Mouse.");
  237.         }
  238.       }
  239.     } // delete
  240.     else
  241.     {
  242.       // do nothing
  243.     } // else
  244.   } // if not CODED
  245. } // func
  246. //
  247. // Other, minor functions ****************************************************
  248. //
  249. void AddLineToElement( int NumberOfStartItem, int NumberOfTargetItem,
  250. int adaptor1, int adaptor2) {
  251.   // add a line
  252.   GraphicalItem itemStart = getElementByID (NumberOfStartItem);
  253.   itemStart.addAdaptor ( new AdaptorType(NumberOfTargetItem, adaptor1, adaptor2) );
  254. }
  255. //
  256. void showGraphical() {
  257.   // show the graphicalItems from the arrayList
  258.   textAlign(LEFT);
  259.   text ( "Graphical Representation"
  260.     + " - "
  261.     + "Move items with left Mouse button. Drag with right mouse button: scale "
  262.     + "(x-direction) and up/down (y-direction).", 20, 14 );
  263.   if (graphicalItems.isEmpty()) {
  264.     text("Graphical Diagram is empty.", 220, 170 );
  265.   }
  266.   else
  267.   {
  268.     for (GraphicalItem myGraphicalItem : graphicalItems) {
  269.       myGraphicalItem.display() ;
  270.     } // for
  271.   } // if else
  272. } // func
  273. //
  274. GraphicalItem getElementByID( int myIdParameter ) {
  275.   // returns object or null
  276.   for (GraphicalItem myGraphicalItem : graphicalItems) {
  277.     if (myGraphicalItem.objectID==myIdParameter) {
  278.       return myGraphicalItem;
  279.     } // if
  280.   } // for
  281.   return null;
  282. } // func
  283. //
  284. GraphicalItem getElementFromTexts( String textHeaderParam, String textNormalParam ) {
  285.   // not in use
  286.   // returns object or null
  287.   for (GraphicalItem myGraphicalItem : graphicalItems) {
  288.     if (myGraphicalItem.textHeader.equals(textHeaderParam) &&
  289.       myGraphicalItem.textNormal.equals(textNormalParam)) {
  290.       return myGraphicalItem;
  291.     } // if
  292.   } // for
  293.   return null;
  294. } // func
  295. //
  296. int getElementNumberFromTexts( String textHeaderParam, String textNormalParam ) {
  297.   // not in use
  298.   // returns number of object or -1
  299.   for (GraphicalItem myGraphicalItem : graphicalItems) {
  300.     if (myGraphicalItem.textHeader.equals(textHeaderParam) &&
  301.       myGraphicalItem.textNormal.equals(textNormalParam)) {
  302.       // return i;
  303.       return myGraphicalItem.getObjectID();
  304.     } // if
  305.   } // for
  306.   return -1;
  307. } // func
  308. //
  309. // ==============================================================
  310. class GraphicalItem {
  311.   //
  312.   PVector Position;   // Pos and size of the whole box
  313.   PVector boxSize;    // Size
  314.   final int headerHeight = 20;  // Height of header text box
  315.   color headerColor;   //  color of header box
  316.   // the type of the item
  317.   int typeOfGraphicalItem;
  318.   // texts
  319.   String textHeader="";
  320.   String textNormal="";
  321.   //
  322.   // where the adaptors lead to: ArrayList of
  323.   // AdaptorType (see class AdaptorType)
  324.   ArrayList<AdaptorType> adaptorTo;  
  325.   //
  326.   // Positions of items own adaptors as x,y
  327.   PVector adaptorNorth;
  328.   PVector adaptorEast;
  329.   PVector adaptorSouth;
  330.   PVector adaptorWest;
  331.   //
  332.   // holds the object's unique ID
  333.   int objectID;
  334.   //
  335.   // constructor ----------
  336.   GraphicalItem(
  337.   int _typeOfGraphicalItem,
  338.   int _x, int _y,
  339.   String _header, String _normalText,
  340.   AdaptorType _adaptorTo,
  341.   color _tempColor) {
  342.     //
  343.     Position = new PVector( _x, _y);
  344.     boxSize  = new PVector( 100, 70 );
  345.     textHeader    = _header;
  346.     textNormal    = _normalText;
  347.     adaptorTo = new ArrayList();
  348.     if (_adaptorTo!=null) {
  349.       adaptorTo.add (new AdaptorType(
  350.       _adaptorTo.adaptorToGraphicalItem,
  351.       _adaptorTo.fromAdaptor,
  352.       _adaptorTo.toAdaptor));
  353.       //adaptorTo [0] = _adaptorTo;
  354.     }
  355.     //
  356.     // type
  357.     typeOfGraphicalItem=_typeOfGraphicalItem;
  358.     //
  359.     if (typeOfGraphicalItem == typeOfGraphicalItemConditional) {
  360.       // Conditional item = triangle
  361.       // calculate the four adaptors pos
  362.       adaptorNorth  = new PVector( boxSize.x/2, 0 );
  363.       adaptorEast   = new PVector( 2*boxSize.x/3+11, boxSize.y/2 );   
  364.       adaptorWest   = new PVector( boxSize.x/3-7, boxSize.y/2 );     
  365.       // rarely used with Conditional:
  366.       adaptorSouth  = new PVector( boxSize.x/2 + 4, boxSize.y );
  367.     }
  368.     else {
  369.       // item = all except Conditional / triangle     
  370.       // calculate the four adaptors pos
  371.       adaptorNorth  = new PVector( boxSize.x/2, 0 );
  372.       adaptorEast   = new PVector( boxSize.x, boxSize.y/2 );   
  373.       adaptorSouth  = new PVector( boxSize.x/2, boxSize.y );
  374.       adaptorWest   = new PVector( 0, boxSize.y/2 );
  375.     }
  376.     //
  377.     headerColor = _tempColor;
  378.     objectID = getUniqueID();
  379.     //
  380.     plausibilityCheck();
  381.   }// constructor
  382.   //
  383.   private void plausibilityCheck () {
  384.     // checks whether there are not plausible parameters, e.g.
  385.     // a defined header with a typeOfGraphicalItem that has no
  386.     // header (header text ignored).
  387.     // Same for color with colorless types.
  388.     //
  389.     // check header text
  390.     if (typeOfGraphicalItem == typeOfGraphicalItemConditional ||
  391.       typeOfGraphicalItem == typeOfGraphicalItemStandardWithoutHeader ||
  392.       typeOfGraphicalItem == typeOfGraphicalItemStartEnd  ) {
  393.       if (!textHeader.trim().equals("")) {
  394.         println("Remark 285: StandardWithoutHeader or Conditional etc. "
  395.           + "has defined header (not shown) with header: '"
  396.           + textHeader
  397.           + "' and normal text: '"
  398.           + textNormal
  399.           + "'. "
  400.           + "Type being: "
  401.           + typeOfGraphicalItemName[typeOfGraphicalItem]
  402.           + ". Header ignored.");
  403.       }
  404.     } // if
  405.     // check color
  406.     if (typeOfGraphicalItem != typeOfGraphicalItemStandardWithHeader &&
  407.       headerColor != black) {
  408.       println("Remark 325: color is set for header "
  409.         + "(headerColor <> 0). Header being: '"
  410.         + textHeader
  411.         + "' and normal text: '"
  412.         + textNormal
  413.         + "'. "
  414.         + "Type being: "
  415.         + typeOfGraphicalItemName[typeOfGraphicalItem]
  416.         + ". Color ignored.");
  417.     } // if
  418.   } // func
  419.   //
  420.   void display() {
  421.     // display a star in the text when selected
  422.     if (selected == objectID) {
  423.       if (textNormal.charAt(textNormal.length()-1) != '*') {
  424.         textNormal+="*";
  425.       }
  426.     }
  427.     else {
  428.       if (textNormal.charAt(textNormal.length()-1) == '*') {
  429.         // un-select
  430.         textNormal=textNormal.substring(0, textNormal.length()-1);
  431.       }
  432.     }
  433.     // display it
  434.     switch (typeOfGraphicalItem) {
  435.     case typeOfGraphicalItemStandardWithHeader:
  436.       displayStandardWithHeader() ;
  437.       break;
  438.     case typeOfGraphicalItemStandardWithoutHeader:
  439.       displayStandardWithoutHeader();
  440.       break;
  441.     case typeOfGraphicalItemConditional:
  442.       displayConditional();
  443.       break;
  444.     case typeOfGraphicalItemStartEnd:
  445.       displayStartEnd();
  446.       break;
  447.     default:
  448.       println("Error occured 245 - unknown typeOfGraphicalItem");
  449.       break;
  450.     } // switch
  451.     //
  452.   } // method
  453.   //
  454.   private void displayStandardWithHeader() {
  455.     fill (headerColor);
  456.     stroke(0);
  457.     // header rect
  458.     rect (Position.x, Position.y,
  459.     boxSize.x, headerHeight);
  460.     fill(244);
  461.     // rect for normal text field (lower half)
  462.     rect (Position.x, Position.y+headerHeight,
  463.     boxSize.x, boxSize.y-headerHeight);   
  464.     fill (0);
  465.     text (textHeader, Position.x+4, Position.y+2, boxSize.x-5, headerHeight);
  466.     text (textNormal, Position.x+4, Position.y+headerHeight+2, boxSize.x-5, boxSize.y-headerHeight);
  467.     // adaptors --------   
  468.     showAdaptors(adaptorTo);
  469.   } // method
  470.   //
  471.   private void displayStandardWithoutHeader() {
  472.     fill(244);
  473.     // rect for text field
  474.     rect (Position.x, Position.y,
  475.     boxSize.x, boxSize.y);   
  476.     fill (0);
  477.     text (textNormal,
  478.     Position.x+4, Position.y+2,
  479.     boxSize.x-5, boxSize.y);
  480.     // adaptors --------
  481.     showAdaptors(adaptorTo) ;
  482.   } // method
  483.   //
  484.   private void displayConditional() {
  485.     // Conditional is triangle
  486.     fill(244);
  487.     triangle (Position.x, Position.y,
  488.     Position.x+boxSize.x+0, Position.y,
  489.     Position.x+boxSize.x/2+5, Position.y + boxSize.y);   
  490.     fill (0);
  491.     textAlign(CENTER);
  492.     text (textNormal,
  493.     Position.x+2, Position.y+2,
  494.     boxSize.x-5, boxSize.y );
  495.     // adaptors ----------
  496.     showAdaptors(adaptorTo) ;
  497.   } // method
  498.   //
  499.   private void displayStartEnd() {
  500.     fill(244);
  501.     ellipseMode(CORNER);
  502.     ellipse (Position.x, Position.y, boxSize.x, boxSize.y);   
  503.     fill (0);
  504.     textAlign(CENTER);
  505.     text (textNormal,
  506.     Position.x+7, Position.y+18,
  507.     boxSize.x-5, boxSize.y );
  508.     // adaptors ------------
  509.     showAdaptors(adaptorTo) ;
  510.   } // method
  511.   //
  512.   private void showAdaptors(ArrayList<AdaptorType> adaptorTo) {
  513.     // adaptors --------
  514.     for (AdaptorType adaptorThis : adaptorTo) {
  515.       if (adaptorThis != null) {
  516.         adaptorThis.display ( this ) ;
  517.       } // if
  518.     } // for
  519.   } // method
  520.   //
  521.   void addAdaptor(AdaptorType _adaptorTo) {
  522.     // appends one line on a existing GraphicalItem
  523.     if (_adaptorTo.adaptorToGraphicalItem > -1) {
  524.       adaptorTo.add (_adaptorTo);
  525.     } // if
  526.   } // method
  527.   //
  528.   boolean isMouseOver() {
  529.     if (mouseX/myScale > Position.x
  530.       && mouseX/myScale < Position.x + boxSize.x
  531.       && mouseY/myScale - myTranslate > Position.y
  532.       && mouseY/myScale - myTranslate < Position.y + boxSize.y) {
  533.       return true;
  534.     } // if
  535.     else {
  536.       return false;
  537.     } // if else
  538.   } // method
  539.   //
  540.   int getObjectID() {
  541.     return objectID;
  542.   } // method
  543.   //
  544.   void delete() {
  545.     // delete one item in 3 steps:
  546.     // 1. delete outgoing Adaptors
  547.     adaptorTo.clear();
  548.     // 2. delete incoming Adaptors   
  549.     deleteAllIncomingAdaptors(this);
  550.     // 3. delete graphicalItem itself
  551.     graphicalItems.remove(this);
  552.   } // method
  553.   //
  554.   private void deleteAllIncomingAdaptors( GraphicalItem myGraphicalItemParameter ) {
  555.     // delete
  556.     // go through all graphicalItems
  557.     for (GraphicalItem myGraphicalItem : graphicalItems) {     
  558.       // when it's different from the one being tested:
  559.       if (myGraphicalItemParameter.objectID != myGraphicalItem.objectID) {
  560.         // check its adaptors --------
  561.         for (AdaptorType adaptorThis : adaptorTo) {
  562.           // When it's leading to the item being deleted
  563.           if (adaptorThis.adaptorToGraphicalItem==myGraphicalItemParameter.objectID) {
  564.             myGraphicalItem.adaptorTo.remove(adaptorThis);
  565.             // adaptorThis.remove();
  566.           } // if
  567.         } // for
  568.       } // for
  569.     } // if
  570.   } // method
  571.   //
  572.   private int getUniqueID() {
  573.     return id++;
  574.   }
  575.   //
  576. } // class
  577. // ==============================================================
  578. class AdaptorType {
  579.   // Represents one connecting line.
  580.   //
  581.   // Start point (FROM) is a point at
  582.   // the GraphicalItem (a box) this
  583.   // AdaptorType-object belongs to.
  584.   // End point (TO) is another GraphicalItem
  585.   // marked by the var adaptorToGraphicalItem
  586.   // which is an Index for the ArrayList
  587.   // graphicalItems.
  588.   // To specify the exakt point at
  589.   // the from-GraphicalItem, the var
  590.   // fromAdaptor denotes whether it's
  591.   // (clockwise) north, east, south or west.
  592.   // And: To specify the exakt point at
  593.   // the to-GraphicalItem, the var
  594.   // toAdaptor denotes whether it's
  595.   // (clockwise) north, east, south or west.
  596.   //
  597.   // Indices of another GraphicalItem
  598.   int adaptorToGraphicalItem  = -1;    // other graphical item
  599.   // from which Adaptor of the four
  600.   int fromAdaptor = adaptorEast;  
  601.   // to which Adaptor of the four 
  602.   int toAdaptor   = adaptorEast;   
  603.   //
  604.   // constructor
  605.   AdaptorType ( int tempAdaptorToGraphicalItem,
  606.   int tempFromAdaptor,
  607.   int tempToAdaptor ) {
  608.     adaptorToGraphicalItem = tempAdaptorToGraphicalItem;
  609.     fromAdaptor = tempFromAdaptor;
  610.     toAdaptor = tempToAdaptor;
  611.   } // constructor
  612.   //
  613.   void display(GraphicalItem startGraphicalItem) {
  614.     // show the line
  615.     if (startGraphicalItem!=null) {
  616.       if (adaptorToGraphicalItem > -1) {
  617.         PVector startVector = getPVector
  618.           (startGraphicalItem, fromAdaptor);
  619.         GraphicalItem toItem = getElementByID(adaptorToGraphicalItem);
  620.         if (toItem!=null) {
  621.           PVector endVector = getPVector
  622.             (toItem, toAdaptor);
  623.           line ( startVector.x, startVector.y,
  624.           endVector.x, endVector.y );
  625.         } // if
  626.       } // if
  627.     } // if
  628.   } // method
  629.   //
  630.   private PVector getPVector(GraphicalItem graphicalItem, int whichAdaptor) {
  631.     // returns x,y for one adaptor "whichAdaptor" on the
  632.     // GraphicalItem named "startGraphicalItem".
  633.     // Can therefore be used for the start point and the end point of
  634.     // a line.
  635.     PVector buffer = new PVector ();
  636.     //
  637.     switch (whichAdaptor) {
  638.     case adaptorNorth:
  639.       buffer.x=graphicalItem.Position.x+graphicalItem.adaptorNorth.x;
  640.       buffer.y=graphicalItem.Position.y+graphicalItem.adaptorNorth.y;
  641.       break;
  642.     case adaptorEast:
  643.       buffer.x=graphicalItem.Position.x+graphicalItem.adaptorEast.x;
  644.       buffer.y=graphicalItem.Position.y+graphicalItem.adaptorEast.y;
  645.       break;
  646.     case adaptorSouth:
  647.       buffer.x=graphicalItem.Position.x+graphicalItem.adaptorSouth.x;
  648.       buffer.y=graphicalItem.Position.y+graphicalItem.adaptorSouth.y;
  649.       break;
  650.     case adaptorWest:
  651.       buffer.x=graphicalItem.Position.x+graphicalItem.adaptorWest.x;
  652.       buffer.y=graphicalItem.Position.y+graphicalItem.adaptorWest.y;
  653.       break;
  654.     default:
  655.       println ("Error 337 - unknown adaptor");
  656.       break;
  657.     } // switch
  658.     return buffer;
  659.   } // method
  660.   //
  661. } // class
  662. // ==============================================================