[prev in list] [next in list] [prev in thread] [next in thread]
List: jedit-devel
Subject: [ jEdit-devel ] TextAreaPainter: text and caret painting
From: Makarius <makarius () sketis ! net>
Date: 2011-06-25 19:57:43
Message-ID: alpine.LNX.1.10.1106252104190.29425 () atbroy100 ! informatik ! tu-muenchen ! de
[Download RAW message or body]
As explained before, I have my own version of token marking and text
painting (now for jedit-4.4.1). The following is about some fine points
of text and caret painting that I've noticed when implementing this in
Scala:
http://isabelle.in.tum.de/repos/isabelle/file/bf7400573617/src/Tools/jEdit/src/text_area_painter.scala
Since I don't know much Java, I need to explain things in terms of Scala.
I hope this can be understood informally as "pseudo-code" for a
corresponding Java program, for people who are not working regularly with
Scala.
* Generally, the architecture of TextAreaPainter is easy to extend: there
are several layers, and the jEdit default setup uses just the same
mechanisms that are available to plugins as well (operations around
TextAreaExtension). Two small things have required some workarounds on my
side, though.
(1) Inner classes TextAreaPainter.PaintText and
TextAreaPainter.PaintCaret are private, which means in order to
remove them one needs to play untyped tricks with reflection:
private def pick_extension(name: String): TextAreaExtension =
{
text_area.getPainter.getExtensions.iterator.
filter(x => x.getClass.getName == name).toList
match {
case List(x) => x
case _ => error("Expected exactly one " + name)
}
}
private val orig_text_painter =
pick_extension("org.gjt.sp.jedit.textarea.TextAreaPainter$PaintText")
This might look like a slight abuse of TextAreaPainter.getExtensions.
If TextAreaPainter would make the standard extensions publicly
available as objects, one could remove them in a statically
typed way.
(2) The object caretExtension (class PaintCaret) is removed/added at each
propertiesChanged event, since it might jump between layers:
BLOCK_CARET_LAYER vs. CARET_LAYER. (Does anybody know the reasons for
these different layers of thin line vs. rectangle caret? I reckon that
one could always paint over or under the text layer, say.)
This means I could not remove the standard caret extension reliably.
Instead I added my own extensions just before and after the usual caret
layers to mask its effect via clipping on the gfx context. (If any
other plugin installs anything tere, it will be masked as well.)
I also had to ignore the blink feature, because that field is private.
BTW, the deeper reason why I wanted my own caret painter is this: using
alternative font styles (notably sub- and superscript), I wanted to have
precise visual feedback cerning the character metrics of the caret
position, not just a static line or rectangle (block caret). It also
helps for non-proportional fonts, especially long mathematical arrows.
So the caret painting moved into my text painter, using
java.awt.font.TextAttribute.SWAP_COLORS on suitable
java.text.AttributedString. Clipping ensures that the standard
caret does not interfere with it.
(3) Precise line boundary. Painting with exotic font styles or reverse
text has lead to some surprises concerning default Java font metrics.
The basic model of TextArea painting seems to be that each line can be
re-painted independently, so they must be disjoint in the gfx view.
Some small overshots or undershots would produce ugly residual spots
when moving the caret between lines, for example. (I have also seen
this with official jEdit text painting and OpenJDK 6, with its lack of
proper Graphics2D.)
So what I did is to have the line text painter introduce a temporay clip
for the precise line height according to jEdit:
gfx.clipRect(x0, y + line_height * i, Integer.MAX_VALUE, line_height)
...
gfx.drawString(...)
See also
http://isabelle.in.tum.de/repos/isabelle/file/bf7400573617/src/Tools/jEdit/src/text_area_painter.scala#l275
for the greater context of this code.
So one might consider fine-tuning of the standard TextArea painter:
* Either do the clipping only for TextAreaPainter.PaintText
individually. (It might be actually relevant in jedit-4.4.1 with
its new font substitution scheme, since alien fonts with slightly
different metrics may be painted over the original line layout in
unexpected ways.)
* Or do the clipping uniformly for the default implementation of
TextAreaExtension.paintScreenLineRange, just before and after the
invocation of the user-provided implementations of paintInvalidLine
and paintValidLine.
This would leave the general paintScreenLineRange entry point open
for advanced plugins, but the default would keep away these worries
from clients.
Anyway, I think TextArea with its flexible layered painting mechanism is
one of the assets of jEdit. At a very early stage of the project, I had a
student trying to make anything like that with Netbeans, but he failed
miserably on all the private/final stuff in their slightly over-engineered
architecture. I am much more comfortable with the jEdit code base now.
Makarius
------------------------------------------------------------------------------
All the data continuously generated in your IT infrastructure contains a
definitive record of customers, application performance, security
threats, fraudulent activity and more. Splunk takes this data and makes
sense of it. Business sense. IT sense. Common sense..
http://p.sf.net/sfu/splunk-d2d-c1
--
-----------------------------------------------
jEdit Developers' List
jEdit-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/jedit-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic