basic support for subexpression highlighting (see also gatchan.jedit.hyperlinks.HyperlinkManager/HyperlinkTextAreaPainter);
authorwenzelm
Sat, 04 Sep 2010 22:00:25 +0200
changeset 39390947c62440026
parent 39376 12dac4b58df8
child 39391 ba17ca3acdd3
basic support for subexpression highlighting (see also gatchan.jedit.hyperlinks.HyperlinkManager/HyperlinkTextAreaPainter);
src/Tools/jEdit/src/jedit/document_view.scala
     1.1 --- a/src/Tools/jEdit/src/jedit/document_view.scala	Sat Sep 04 00:59:03 2010 +0200
     1.2 +++ b/src/Tools/jEdit/src/jedit/document_view.scala	Sat Sep 04 22:00:25 2010 +0200
     1.3 @@ -12,11 +12,12 @@
     1.4  
     1.5  import scala.actors.Actor._
     1.6  
     1.7 -import java.awt.event.{MouseAdapter, MouseEvent}
     1.8 +import java.awt.event.{MouseAdapter, MouseMotionAdapter, MouseEvent, FocusAdapter, FocusEvent}
     1.9  import java.awt.{BorderLayout, Graphics, Dimension, Color, Graphics2D}
    1.10  import javax.swing.{JPanel, ToolTipManager}
    1.11  import javax.swing.event.{CaretListener, CaretEvent}
    1.12  
    1.13 +import org.gjt.sp.jedit.OperatingSystem
    1.14  import org.gjt.sp.jedit.gui.RolloverButton
    1.15  import org.gjt.sp.jedit.textarea.{JEditTextArea, TextArea, TextAreaExtension, TextAreaPainter}
    1.16  import org.gjt.sp.jedit.syntax.SyntaxStyle
    1.17 @@ -161,6 +162,29 @@
    1.18    }
    1.19  
    1.20  
    1.21 +  /* subexpression highlighting */
    1.22 +
    1.23 +  private var highlight_point: Option[(Int, Int)] = None
    1.24 +
    1.25 +  private val focus_listener = new FocusAdapter {
    1.26 +    override def focusLost(e: FocusEvent) { highlight_point = None }
    1.27 +  }
    1.28 +
    1.29 +  private val mouse_motion_listener = new MouseMotionAdapter {
    1.30 +    override def mouseMoved(e: MouseEvent) {
    1.31 +      val control = if (OperatingSystem.isMacOS()) e.isMetaDown else e.isControlDown
    1.32 +      def refresh()
    1.33 +      {
    1.34 +        val offset = text_area.xyToOffset(e.getX(), e.getY())
    1.35 +        text_area.invalidateLine(model.buffer.getLineOfOffset(offset))
    1.36 +      }
    1.37 +      if (!model.buffer.isLoaded) highlight_point = None
    1.38 +      else if (!control) { highlight_point = None; refresh() }
    1.39 +      else { highlight_point = Some((e.getX(), e.getY())); refresh() }
    1.40 +    }
    1.41 +  }
    1.42 +
    1.43 +
    1.44    /* text_area_extension */
    1.45  
    1.46    private val text_area_extension = new TextAreaExtension
    1.47 @@ -173,6 +197,22 @@
    1.48          val snapshot = model.snapshot()
    1.49          val saved_color = gfx.getColor
    1.50          val ascent = text_area.getPainter.getFontMetrics.getAscent
    1.51 +
    1.52 +        // subexpression markup
    1.53 +        val subexp_markup: PartialFunction[Text.Info[Any], Option[Text.Range]] =
    1.54 +        {
    1.55 +          case Text.Info(range, XML.Elem(Markup(Markup.ML_TYPING, _), _)) => Some(range)
    1.56 +        }
    1.57 +        val subexp_range: Option[Text.Range] =
    1.58 +          highlight_point match {
    1.59 +            case Some((x, y)) =>
    1.60 +              val offset = text_area.xyToOffset(x, y)
    1.61 +              val markup =
    1.62 +                snapshot.select_markup(Text.Range(offset, offset + 1))(subexp_markup)(None)
    1.63 +              if (markup.hasNext) markup.next.info else None
    1.64 +            case None => None
    1.65 +          }
    1.66 +
    1.67          try {
    1.68            for (i <- 0 until physical_lines.length) {
    1.69              if (physical_lines(i) != -1) {
    1.70 @@ -189,6 +229,19 @@
    1.71                  gfx.fillRect(r.x, y + i * line_height, r.length, line_height)
    1.72                }
    1.73  
    1.74 +              // subexpression highlighting
    1.75 +              if (subexp_range.isDefined) {
    1.76 +                val range = snapshot.convert(subexp_range.get)
    1.77 +                if (line_range.overlaps(range)) {
    1.78 +                  Isabelle.gfx_range(text_area, line_range.restrict(range)) match {
    1.79 +                    case None =>
    1.80 +                    case Some(r) =>
    1.81 +                      gfx.setColor(Color.black)
    1.82 +                      gfx.drawRect(r.x, y + i * line_height, r.length, line_height - 1)
    1.83 +                  }
    1.84 +                }
    1.85 +              }
    1.86 +
    1.87                // squiggly underline
    1.88                for {
    1.89                  Text.Info(range, color) <-
    1.90 @@ -315,6 +368,8 @@
    1.91    {
    1.92      text_area.getPainter.
    1.93        addExtension(TextAreaPainter.LINE_BACKGROUND_LAYER + 1, text_area_extension)
    1.94 +    text_area.addFocusListener(focus_listener)
    1.95 +    text_area.getPainter.addMouseMotionListener(mouse_motion_listener)
    1.96      text_area.addCaretListener(caret_listener)
    1.97      text_area.addLeftOfScrollBar(overview)
    1.98      session.commands_changed += commands_changed_actor
    1.99 @@ -323,8 +378,10 @@
   1.100    private def deactivate()
   1.101    {
   1.102      session.commands_changed -= commands_changed_actor
   1.103 +    text_area.removeFocusListener(focus_listener)
   1.104 +    text_area.getPainter.removeMouseMotionListener(mouse_motion_listener)
   1.105 +    text_area.removeCaretListener(caret_listener)
   1.106      text_area.removeLeftOfScrollBar(overview)
   1.107 -    text_area.removeCaretListener(caret_listener)
   1.108      text_area.getPainter.removeExtension(text_area_extension)
   1.109    }
   1.110  }
   1.111 \ No newline at end of file