src/Tools/Graphview/metrics.scala
author wenzelm
Sun Jan 18 12:36:25 2015 +0100 (2015-01-18)
changeset 59388 04cdfd536e7d
parent 59384 c75327a34960
child 59389 c427f3de9050
permissions -rw-r--r--
tuned metrics;
wenzelm@59290
     1
/*  Title:      Tools/Graphview/metrics.scala
wenzelm@59290
     2
    Author:     Makarius
wenzelm@59290
     3
wenzelm@59290
     4
Physical metrics for layout and painting.
wenzelm@59290
     5
*/
wenzelm@59290
     6
wenzelm@59290
     7
package isabelle.graphview
wenzelm@59290
     8
wenzelm@59290
     9
wenzelm@59290
    10
import isabelle._
wenzelm@59290
    11
wenzelm@59290
    12
import java.awt.{Font, RenderingHints}
wenzelm@59290
    13
import java.awt.font.FontRenderContext
wenzelm@59384
    14
import java.awt.geom.Rectangle2D
wenzelm@59290
    15
wenzelm@59290
    16
wenzelm@59290
    17
object Metrics
wenzelm@59290
    18
{
wenzelm@59290
    19
  val rendering_hints: RenderingHints =
wenzelm@59290
    20
    new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON)
wenzelm@59290
    21
wenzelm@59290
    22
  val font_render_context: FontRenderContext =
wenzelm@59290
    23
    new FontRenderContext(null, true, false)
wenzelm@59290
    24
wenzelm@59290
    25
  def apply(font: Font): Metrics = new Metrics(font)
wenzelm@59290
    26
wenzelm@59290
    27
  val default: Metrics = apply(new Font("Helvetica", Font.PLAIN, 12))
wenzelm@59290
    28
}
wenzelm@59290
    29
wenzelm@59290
    30
class Metrics private(val font: Font)
wenzelm@59290
    31
{
wenzelm@59384
    32
  def string_bounds(s: String): Rectangle2D = font.getStringBounds(s, Metrics.font_render_context)
wenzelm@59290
    33
  private val mix = string_bounds("mix")
wenzelm@59290
    34
  val space_width = string_bounds(" ").getWidth
wenzelm@59290
    35
  def char_width: Double = mix.getWidth / 3
wenzelm@59290
    36
  def height: Double = mix.getHeight
wenzelm@59290
    37
  def ascent: Double = font.getLineMetrics("", Metrics.font_render_context).getAscent
wenzelm@59290
    38
wenzelm@59384
    39
  def gap: Double = mix.getWidth.ceil
wenzelm@59302
    40
wenzelm@59388
    41
  def dummy_size2: Double = (char_width / 2).ceil
wenzelm@59384
    42
wenzelm@59384
    43
  def node_width2(lines: List[String]): Double =
wenzelm@59388
    44
    (((0.0 /: lines)({ case (w, s) => w max string_bounds(s).getWidth }) + 2 * char_width) / 2).ceil
wenzelm@59302
    45
wenzelm@59384
    46
  def node_height2(num_lines: Int): Double =
wenzelm@59388
    47
    ((height.ceil * (num_lines max 1) + char_width) / 2).ceil
wenzelm@59384
    48
wenzelm@59384
    49
  def level_height2(num_lines: Int, num_edges: Int): Double =
wenzelm@59384
    50
    (node_height2(num_lines) + gap) max (node_height2(1) * (num_edges max 5))
wenzelm@59384
    51
wenzelm@59384
    52
  object Pretty_Metric extends Pretty.Metric
wenzelm@59384
    53
  {
wenzelm@59384
    54
    val unit = space_width max 1.0
wenzelm@59384
    55
    def apply(s: String): Double = if (s == "\n") 1.0 else string_bounds(s).getWidth / unit
wenzelm@59384
    56
  }
wenzelm@59290
    57
}
wenzelm@59290
    58