isac-java/src/java/isac/gui/mawen/editor/AstComponent.scala
author Walther Neuper <walther.neuper@jku.at>
Fri, 26 Mar 2021 10:45:05 +0100
changeset 5239 b4e3883d7b66
parent 5229 6bf0e95981e3
permissions -rw-r--r--
reset mathematics-engine to Isabelle2015

note: for this version libisabelle was available,
which connects front-end (Java) and back-end (Isabelle/ML)
s1520454056@5025
     1
package isac.gui.mawen.editor
s1520454056@5025
     2
wneuper@5199
     3
import isac.gui.mawen.editor.Box.DrawBox
wneuper@5199
     4
import isac.gui.mawen.syntax.Ast._
wneuper@5199
     5
import isac.interfaces.IEditor
walther@5239
     6
import edu.tum.cs.isabelle.api.Implementation
wneuper@5199
     7
s1520454056@5025
     8
import javax.swing._
s1520454056@5025
     9
import java.awt._
s1520454056@5025
    10
import java.awt.geom._
s1520454056@5025
    11
import java.awt.font._
s1520454056@5029
    12
import java.awt.event._
s1520454056@5029
    13
import java.awt.font._
s1520454056@5057
    14
import org.drools.xml.ExtensibleXmlParser.Null
s1520454056@5093
    15
import scala.collection.immutable.List
s1520454056@5162
    16
wneuper@5165
    17
/**
wneuper@5165
    18
 * The Java Swing component for a formula
wneuper@5165
    19
 * represented by an <code>Ast</code>
wneuper@5165
    20
 */
s1520454056@5160
    21
class AstComponent(var ast: Ast) extends JComponent with AstContainer with MouseListener with MouseMotionListener {
s1520454056@5057
    22
s1520454056@5057
    23
  addMouseListener(this)
s1520454056@5057
    24
  addMouseMotionListener(this)
s1520454056@5057
    25
  var pressedMousePoint : Point = null
s1520454056@5144
    26
  var marker : Rectangle = new Rectangle()
wneuper@5214
    27
  // list of boxes touched by mouse while drawing a rectangle; the outmost is relevant 
s1520454056@5162
    28
  var markedBoxes : List[DrawBox] = List.empty[DrawBox]
s1520454056@5162
    29
  var box : DrawBox  = null
s1520454056@5144
    30
  setFocusable(true)
s1520454056@5144
    31
  addKeyListener(EventUtil.CreateKeyEventHandler(this))
s1520454056@5160
    32
  addMouseWheelListener(EventUtil.CreateMouseWheelHandler(this))
s1520454056@5112
    33
  setSize(50,150)
s1520454056@5025
    34
  
s1520454056@5171
    35
  new Thread(new Runnable() {
s1520454056@5171
    36
    def run() {
s1520454056@5171
    37
      while (true) {
s1520454056@5212
    38
        Thread.sleep(250);
s1520454056@5177
    39
        repaint()
s1520454056@5171
    40
      }
s1520454056@5171
    41
    }
s1520454056@5171
    42
  }).start()
s1520454056@5171
    43
  
s1520454056@5091
    44
  def setAst(ast: Ast) = {
s1520454056@5091
    45
    this.ast = ast
s1520454056@5091
    46
    repaint()
s1520454056@5091
    47
  }
s1520454056@5129
    48
  def getAst() : Ast = this.ast
wneuper@5199
    49
s1520454056@5057
    50
  override def paint(g: Graphics) = {
s1520454056@5168
    51
    Settings.g = g
s1520454056@5057
    52
    val g2 = g.asInstanceOf[Graphics2D]
s1520454056@5057
    53
    // enable antialiasing for Text
s1520454056@5057
    54
    val rh = new RenderingHints(
s1520454056@5057
    55
      RenderingHints.KEY_TEXT_ANTIALIASING,
s1520454056@5057
    56
      RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
s1520454056@5057
    57
    g2.setRenderingHints(rh);
s1520454056@5057
    58
    // white background
s1520454056@5057
    59
    g.setColor(Color.WHITE)
s1520454056@5057
    60
    g.fillRect(0, 0, getWidth, getHeight)
s1520454056@5057
    61
    g.setColor(Color.BLACK)
s1520454056@5057
    62
    g.translate(Settings.translateX, Settings.translateY)
s1520454056@5057
    63
    g2.scale(Settings.zoom, Settings.zoom)
s1520454056@5164
    64
    Settings.fillStringbounds(ast, g2)
s1520454056@5164
    65
    box =  CalcUtil.assembleBoxes(ast, (box: DrawBox) => 
s1520454056@5093
    66
        {
s1520454056@5101
    67
          if (EventUtil.foreachBoxFunction != null) {
s1520454056@5101
    68
            EventUtil.foreachBoxFunction(g2, box)
s1520454056@5093
    69
          }
s1520454056@5057
    70
        }
s1520454056@5101
    71
      )
s1520454056@5213
    72
      BoxUtil.draw(box , g)
s1520454056@5108
    73
      setSize((box.width * Settings.zoom).round + 50 + Settings.translateX, Math.max((box.height * Settings.zoom).round, 50)  + Settings.translateY)
s1520454056@5108
    74
      setPreferredSize(getSize)
s1520454056@5218
    75
      
s1520454056@5144
    76
      g.drawRect(marker.x, marker.y, marker.width, marker.height)
s1520454056@5057
    77
  }
wneuper@5199
    78
wneuper@5185
    79
  // /--- enforced by trait MouseListener --------------------------------------\
wneuper@5199
    80
	def mouseEntered(e: MouseEvent) {}
wneuper@5199
    81
	def mouseExited(e: MouseEvent ) {}
s1520454056@5029
    82
	def mousePressed(e: MouseEvent ) {
s1520454056@5213
    83
	  AstInfoUtil.FindBox(ast) match {
s1520454056@5213
    84
	    case Some(boxAst) => {
s1520454056@5213
    85
	      ast =TransformAstUtil.Update(ast, boxAst, TransformAstUtil.UnBox)    
s1520454056@5213
    86
	    }
s1520454056@5213
    87
	    case None => {}
s1520454056@5144
    88
	  }
s1520454056@5213
    89
	 
s1520454056@5175
    90
	  val cursorAst : Ast = AstInfoUtil.FindCursor(ast)
s1520454056@5175
    91
	  if (cursorAst != null) {
s1520454056@5175
    92
  	  ast =TransformAstUtil.Update(ast, cursorAst , TransformAstUtil.CursorToAst)    
s1520454056@5175
    93
	  }
s1520454056@5057
    94
		pressedMousePoint = new Point ( Settings.translateX - e.getX , Settings.translateY - e.getY)
s1520454056@5144
    95
		marker.setLocation((e.getX / Settings.zoom ).round   -  (Settings.translateX / Settings.zoom).round, 
s1520454056@5144
    96
		                   (e.getY / Settings.zoom ).round   -  (Settings.translateY / Settings.zoom).round)
s1520454056@5029
    97
	}
s1520454056@5029
    98
	def mouseReleased(e: MouseEvent ) {
s1520454056@5057
    99
		pressedMousePoint = null
s1520454056@5144
   100
		marker.setSize(0, 0)
s1520454056@5187
   101
		findHighestBoxOf(box, markedBoxes) match {
s1520454056@5187
   102
		  case Some(highest) => {
s1520454056@5187
   103
		    this.ast = TransformAstUtil.Update(ast, highest.ast, TransformAstUtil.Box)
s1520454056@5187
   104
		  }
s1520454056@5187
   105
		  case None => {}
s1520454056@5187
   106
		}
s1520454056@5162
   107
		markedBoxes = List.empty[DrawBox]
s1520454056@5144
   108
		repaint()
s1520454056@5029
   109
	}
s1520454056@5029
   110
	def mouseClicked(e: MouseEvent ) {
s1520454056@5206
   111
	  if (e.isControlDown()) {
s1520454056@5213
   112
	    AstInfoUtil.FindBox(ast) match {
s1520454056@5213
   113
	      case Some(boxAst) =>  ast =TransformAstUtil.Update(ast, boxAst, TransformAstUtil.UnBox)
s1520454056@5213
   114
	      case None => {}
s1520454056@5213
   115
	    }
s1520454056@5101
   116
		  EventUtil.foreachBoxFunction = EventUtil.doInBox(e.getPoint,
s1520454056@5093
   117
		      (g, box) => {
s1520454056@5093
   118
  	        ast = TransformAstUtil.Update(ast, box.ast, TransformAstUtil.AstToCursor)
s1520454056@5218
   119
  	        EventUtil.foreachBoxFunction = null;
s1520454056@5093
   120
  	        repaint()
s1520454056@5093
   121
		      }
s1520454056@5093
   122
		    );
s1520454056@5057
   123
		}
s1520454056@5057
   124
		repaint()
s1520454056@5029
   125
	}
s1520454056@5057
   126
  def mouseDragged(e:MouseEvent) {
s1520454056@5144
   127
    if (e.isControlDown() &&  Settings.isdraggingAllowed) {
s1520454056@5108
   128
      if (pressedMousePoint != null) {
s1520454056@5108
   129
    	  Settings.translateX = e.getX + pressedMousePoint.x  
s1520454056@5108
   130
    	  Settings.translateY = e.getY + pressedMousePoint.y 
s1520454056@5108
   131
    	  
s1520454056@5108
   132
    	  repaint()
s1520454056@5108
   133
  	  }
s1520454056@5108
   134
    }
s1520454056@5144
   135
    else {
s1520454056@5144
   136
      marker.setSize(((e.getX / Settings.zoom).round - marker.x )  - (Settings.translateX / Settings.zoom).round, 
s1520454056@5144
   137
                     ((e.getY / Settings.zoom).round - marker.y ) - (Settings.translateY / Settings.zoom).round)
s1520454056@5144
   138
      EventUtil.foreachBoxFunction = (g, b) => {
s1520454056@5162
   139
        if (Box.BoxIn(b, marker) && Box.isLeaf(b)) {
s1520454056@5162
   140
          Box.draw(b, g, false)
s1520454056@5144
   141
          if (!markedBoxes.contains(b))
s1520454056@5144
   142
            markedBoxes = b :: markedBoxes 
s1520454056@5144
   143
        }
s1520454056@5144
   144
      }
s1520454056@5144
   145
      repaint()
s1520454056@5144
   146
    }
s1520454056@5057
   147
	}
s1520454056@5057
   148
	def mouseMoved(e: MouseEvent ) {
s1520454056@5218
   149
	  if (Settings.drawBoxesOnMouseMove) {
s1520454056@5218
   150
	    EventUtil.drawBoxAt(e.getPoint())
s1520454056@5218
   151
	  }
s1520454056@5218
   152
	  repaint()
s1520454056@5057
   153
	}
wneuper@5185
   154
  // \--- enforced by trait MouseMotionListener --------------------------------/
s1520454056@5187
   155
s1520454056@5187
   156
  def findHighestBoxOf(rootbox: DrawBox, markedBoxes : List[DrawBox]) : Option[DrawBox] = {
s1520454056@5178
   157
    if (markedBoxes != null && rootbox != null && rootbox.children != null) {
s1520454056@5178
   158
      if (markedBoxes.forall(x => Box.Contains(rootbox,x)) && 
s1520454056@5178
   159
          ! rootbox.children.exists(x => markedBoxes.forall(y => Box.Contains(x, y)))
s1520454056@5178
   160
        ) {
s1520454056@5187
   161
        return Some(rootbox)
s1520454056@5178
   162
        
s1520454056@5178
   163
      } else if (markedBoxes.forall(x => Box.Contains(rootbox, x)) && 
s1520454056@5178
   164
          rootbox.children.exists(x => markedBoxes.forall(y => Box.Contains(x, y)))) {
s1520454056@5178
   165
        
s1520454056@5178
   166
        for( box <- rootbox.children) {
s1520454056@5187
   167
          findHighestBoxOf(box, markedBoxes) match {
s1520454056@5187
   168
            case Some(box) => return Some(box)
s1520454056@5187
   169
            case None => {}
s1520454056@5187
   170
          }          
s1520454056@5144
   171
        }
s1520454056@5144
   172
      }
s1520454056@5144
   173
    }
s1520454056@5187
   174
    return None
s1520454056@5144
   175
  }
wneuper@5199
   176
  
s1520454056@5029
   177
}