/**************************************************************************
* Copyright (c) 2001, 2002, 2003 by Acunia N.V. All rights reserved. *
* *
* This software is copyrighted by and is the sole property of Acunia N.V. *
* and its licensors, if any. All rights, title, ownership, or other *
* interests in the software remain the property of Acunia N.V. and its *
* licensors, if any. *
* *
* This software may only be used in accordance with the corresponding *
* license agreement. Any unauthorized use, duplication, transmission, *
* distribution or disclosure of this software is expressly forbidden. *
* *
* This Copyright notice may not be removed or modified without prior *
* written consent of Acunia N.V. *
* *
* Acunia N.V. reserves the right to modify this software without notice. *
* *
* Acunia N.V. *
* Philips-site 5, box 3 info@acunia.com *
* 3001 Leuven http://www.acunia.com *
* Belgium - EUROPE *
**************************************************************************/
package com.acunia.wonka.rudolph.peers;
import java.awt.*;
/*
** The TextArea Painter class handles the calculation of the text visible in the TextArea's viewport, including the calculation of the
** insert point (from mouse coordinates) or the selected text; also handles the colors in which the area will be displayed;
** (note that the actual painting is forwarded to the RudolphTextAreaPeer plug-in);
** it is a helper class to transfer screen point settings between textArea and painter
** the data to be transferred is:
** => the line of the current point
** => the x-width of the current point, either in (fixed-widht) characters, or in pixels
** => the position of the character the point is in in the painters text buffer (As the buffer does not store endline characters,
** this may be less then the position in the original text)
*/
public abstract class TextAreaPainter {
/*
** Variables
*/
/*
** the viewport in pixels
*/
protected Dimension viewport;
/*
** maximum textlines width == textlineEnd.length
*/
/*
** vertical textlines offset
*/
protected int lineOffset;
/*
** Font and colors
*/
protected Font painterFont;
protected FontMetrics painterMetrics;
//protected int painterCharWidth; // = fm.getMaxAdvance for fixed width characters, -1 for variable width
protected Color[] textColors = RudolphPeer.getBarColors();
/*
** text buffer and text start/stop position arrays
*/
//text to display and text offset arrays: (replace by textbuffer and offset asap)
protected char[] textBuffer;
protected int[] textlineEnd;
protected int[] viewTextOffset;
protected int[] viewTextLength;
protected boolean drawCursor = false;
/*
** Constructor
*/
public TextAreaPainter(Font textfont, FontMetrics metrics, String text, Dimension size, Color[] colors) {
// initialise Dimensions,
viewport = new Dimension(RudolphTextAreaPeer.getInnerwidth(size.width), RudolphTextAreaPeer.getLines(size.height,metrics));
if(viewport.width<0) {
viewport.width=0;
}
// default colors, font
textColors = colors;
painterFont = textfont; //RudolphPeer.DEFAULT_FONT;
painterMetrics = metrics;
//System.out.println("... new TextAreaPainter: font:"+painterFont+" charheight:"+painterMetrics.getHeight()
// +" size=("+size.width+", "+size.height+")");
//text and text arrays
setImage(text);
}
/*
** Constructor short form for derived classes
*/
public TextAreaPainter(FontMetrics metrics, Dimension size, Color[] colors) {
// initialise Dimensions,
viewport = new Dimension(RudolphTextAreaPeer.getInnerwidth(size.width), RudolphTextAreaPeer.getLines(size.height,metrics));
if(viewport.width<0) {
viewport.width=0;
}
// default colors, font
textColors = colors;
}
/*
** get and set screen sizes
*/
public Dimension getScreenSize(int chars, int lines) {
return new Dimension(RudolphTextAreaPeer.getScreenSize( chars*painterMetrics.charWidth('a')), RudolphTextAreaPeer.getHeight(lines,painterMetrics));
}
public int getMaxAdvance() {
// one click at the horizontal painter should ALWAYS advance you one char
return painterMetrics.getMaxAdvance();
}
public int getBorder() {
// We assume a border for mouse scrolling of half the font's height
return painterMetrics.getHeight()/2;
}
/*
** new screen size in pixels
*/
public void setSize(Dimension newsize) {
//width in pixels
viewport.width = RudolphTextAreaPeer.getInnerwidth(newsize.width); //the effective width without the painters borders
//height in character
viewport.height = RudolphTextAreaPeer.getLines(newsize.height,painterMetrics);
//new visible text line parts
calculateVisibleLineparts();
}
/*
** return viewport (width in pixels, height in lines)
*/
public int getViewportWidth() {
return viewport.width;
}
public int getViewportLines() {
return viewport.height;
}
/*
** return Maximum width in pixels, height in lines
*/
public int getMaximumWidth(){
return viewport.width;
}
public int getMaximumLines(){
return textlineEnd.length;
}
/*
** text offset (in pixels), line offset(in lines)
*/
public int getTextOffset() {
// no scrolling text => text offset is always 0
return 0;
}
public int getLineOffset() {
return lineOffset;
}
public Point getOffset() {
//return text offset == 0 and line offset
return new Point(0, lineOffset);
}
public void setTextOffset(int offset) {
// do nothing: as no scrolling text, offset is never used
}
public void setLineOffset(int offset) {
lineOffset = offset;
}
public void setOffset(int offsetx, int offsety) {
// disregard text offset (not used), but set line offset
lineOffset = offsety;
}
/*
** The colors
*/
public void setTextColors(Color back, Color font) {
textColors = RudolphPeer.getBarColors(back, font);
}
public void setTextColors(Color[] newcolors) {
if(newcolors.length >=5) {
textColors = newcolors;
}
}
public Color[] getTextColors() {
return textColors;
}
public Color getBackground() {
return textColors[0];
}
public Color getForeground() {
return textColors[4];
}
/*
** Text methods
*/
public void setImage(String text) {
//Calculate number of lines
int breaks = 0;
int pos=0;
while((pos=text.indexOf('\n',pos+1))>=0) {
breaks++;
}
//initialise line buffers
textBuffer = new char[text.length()-breaks];// we suppress all breaks in the buffer text
textlineEnd = new int[breaks+1];
viewTextOffset = new int[breaks+1];
viewTextLength = new int[breaks+1];
//fill in the buffers up to the last line
int bufstart=0;
int textstart=0;
for(int i=0; i<breaks; i++) {
pos = text.indexOf('\n',textstart);
text.getChars(textstart,pos,textBuffer,bufstart);
textlineEnd[i] = bufstart + pos - textstart;
bufstart=textlineEnd[i];
textstart =pos+1;
}
//last line
text.getChars(textstart,text.length(),textBuffer,bufstart);
textlineEnd[breaks] = textBuffer.length;
//System.out.println("textarea new text <"+new String(textBuffer,0,textBuffer.length)+"> "+textlineEnd.length+" lines");
if(viewport.width>0) {
//if there is a space to show them in, build a new set of visible text arrays
calculateVisibleLineparts();
}
}
/*
** Calculate the part of the text that is visible in the current textrea viewport
** these function MUST be overwritten by the subclasses for wrapping/scrolling with fixedwidth font/variable width font
*/
abstract protected void calculateVisibleLineparts() ;
/*
** Calculate a position on the screen into an array of data : (vertical)line,(horizontal) character or offset and character in text buffer
** Calculate a character in the original text into an array of data :
** the returned data is a 4-int array containing
** int 0: position of the selected character in the original text
** int 1: (vertical)line the selected char is in
** int 2: (Fixed width font) : the number of the selected char in the current line
** (variable width font) : the offset in pixels from text start to the selected char
** int 3: position of the selected character in the painter's text buffer
** these functions MUST be overwritten by the subclasses for wrapping/scrolling with fixedwidth font/variable width font
*/
abstract public void setScreenPosition(int x, int y, int[] pointdata) ;
abstract public void setScreenPosition(int pos, int[] pointdata) ;
abstract public void setScreenPositionLine(int line, int offset, int[] pointdata) ;
/*
** These are debug functions for a basic TextArea behavior: only print the lines as far as they are visible, no scrolling
** these functions MUST be overwritten
* /
/*
** calculate lines, startChars and StopChars for given text, viewport and offset
** in the basic version, this only displays the first characters of the text, up to the right screen end
* /
protected void calculateVisibleLineparts() {
//System.out.println("TextAreaPainter,calculating visible lines for width="+viewport.width);
//security
if(textBuffer.length<=0 || viewport.width<=0) {
textlineEnd = new int[0];
viewTextOffset = new int[0];
viewTextLength = new int[0];
return;
}
int start=0;
for(int i=0;i<textlineEnd.length;i++) {
viewTextOffset[i] = start;
// last char that can be displayed on the line
viewTextLength[i] = RudolphPeer.getChars(viewport.width,start,textBuffer,painterMetrics);
if(viewTextLength[i]>textlineEnd[i]) {
// last char later then line end => length = complete line length
viewTextLength[i] = textlineEnd[i]-start;
}
else {
viewTextLength[i]-=start; // text longer then line => line length = last char of line - first of line
}
start=textlineEnd[i];
}
}
/*
** screen position to position in displayed text and vice versa
** => newposition[0] : position of the selected character in the original text
** => newposition[1] : line of the selected character on the screen
** => newposition[2] : horizontal offset in pixels (or offset calculation value) of the selected character from the left side of the screen
** => newposition[3] : position of the selected character in the TextPainter's text buffer (the text without the \n line breaks)
* /
public void setScreenPosition(int x, int y, int[] pointData) {
//security
if(viewport.width<=0 || viewport.height<=0 ||textlineEnd.length<=0 ) {
return;
}
// no of lines on screen, with offset
pointdata[1] = RudolphTextAreaPeer.getLines(y, painterMetrics) + lineOffset;
if(pointdata[1]>=textlineEnd.length) // deeper then last line
pointdata[1]= textlineEnd.length-1;
// x-position of the line in pixels, in chars
pointdata[3]= RudolphPeer.getChars(x,viewTextOffset[pointdata[1]],textBuffer,painterMetrics);
int chars=pointdata[3]-viewTextOffset[pointdata[1]];
if(pointdata[3]>textlineEnd[pointdata[1]]) {
//calculated maximum width is larger then actual textline width => adjust to end of line
pointdata[3]= textlineEnd[pointdata[1]];
chars = pointdata[3]-viewTextOffset[pointdata[1]];
}
pointdata[2]=painterMetrics.charsWidth(textBuffer, viewTextOffset[pointdata[1]], chars );
// in text string instead of text buffer, each line is ended by a '\n' sign => add 1 extra char for every line before current pos
return pointdata[3] + pointdata[1];
}
public void setScreenPosition(int pos, int[] pointdata) {
//System.out.println( "TextAreaPainter.setScreenPosition : finding data for TextPoint pos "+pos);
//security
if(viewport.width<=0 || viewport.height<=0 ||textlineEnd.length<=0 ) {
return;
}
//security
if(pos<0) {
//no selection
//setData(int line, int chars, int offset) => setBounds(0,line, offset, chars)
pointdata[0] = 0;
pointdata[1] = -1;
pointdata[3] = -1;
pointdata[2] = -1;
}
else if( pos >=(textBuffer.length+textlineEnd.length-1)) {
//passed the end of buffer
//setData(int line, int chars, int offset) => setBounds(0,line, offset, chars)
pointdata[1]=textlineEnd.length-1;
pointdata[3]= textBuffer.length;
pointdata[2] = painterMetrics.charsWidth(textBuffer,viewTextOffset[pointdata[1]],textBuffer.length-viewTextOffset[pointdata[1]]);
}
else {
// scan all lines until we found a line end bigger then the desired possition (as the textbuffer does not count the \n
// endings at each line, subtract an ending char from the pos for each line to obtain the buffer position just as well
pointdata[1]=0;
while(pos>textlineEnd[pointdata[1]]) {
pointdata[1]++;
pos--;
}
pointdata[3] = pos;
pointdata[2]= painterMetrics.charsWidth(textBuffer,viewTextOffset[pointdata[1]],pos-viewTextOffset[pointdata[1]]);
}
}
/*
** paint
*/
abstract public void paint (int width, int height, int cursorline, int cursoroffset, int cursorscreenpos, Graphics g) ;
abstract public void paint(int width, int height, int startline, int startbufferoffset, int starthorizontaloffset,
int stopline, int stopbufferoffset, int stophorizontaloffset,Graphics g) ;
/*
** Static function to build a wrapping or scrolling, fixed or variable charwidth TextArea painter, depending on the type of font
** and on the presence of a horizontal scrollbar
** inthe fiinal version, this will be th only <real> function from class TextAreaPainter that is callde directly.
** as all other functions relate to the derived scrolling/wrapping/fixedwidth/variable-width classes
** and call the derived functions of these
*/
public static TextAreaPainter getNewPainter(Font newfont, String text, Color[] colors, Dimension screen, boolean scrolling) {
TextAreaPainter newpainter;
if( newfont == null) {
newfont = RudolphTextAreaPeer.DEFAULT_FONT;
}
FontMetrics metrics = new FontMetrics(newfont);
int maxwidth = metrics.getMaxAdvance();
if(scrolling && maxwidth> metrics.charWidth('i') ) {
// => variable width & scrolling
newpainter = new TextAreaPainter_ScrollingVarFont(newfont,metrics, text, screen,colors);
}
else if(scrolling) {
//fixed width scrolling
newpainter = new TextAreaPainter_ScrollingFixFont(newfont,metrics,maxwidth, text, screen,colors);
}
else if( maxwidth> metrics.charWidth('i') ) {
// => variable width && wrapping
newpainter = new TextAreaPainter_WrappingVarFont(newfont,metrics,text, screen, colors);
}
else {
//fixed width wrapping
newpainter = new TextAreaPainter_WrappingFixFont(newfont,metrics,maxwidth,text, screen, colors);
}
return newpainter;
}
public void setCursor(boolean enabled) {
drawCursor = enabled;
}
}