/**************************************************************************
* 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.*;
/*
** TextArea Painter for scrolling texts:
** => features:
** scrolling along a horizontal scrollbar: the lext lines are no longer limited to the viewports width.
** A horizontal scrollbar searches out the parts of the text to be shown. As the scrollbar itself is handled by the main class,
** the desired visible part is given to the painter by specifying a horizontal offset
** => Programming:
** - Next to the viewport width, also notion of a maximum line width and a current line offset
** - implementation of getMaximumWidth, getTextOffset, setTextOffset, getOffset & setOffset. if the offset is changed also recalculate
** the visible parts
** - rewriting calculateVisibleLineparts / new algotithm for viewTextOffset and viewTextLength arrays
** in order to let them show the lines starting at a certain offset
** - rewriting setScreenPosition functions to take into account the offset of the text lines
*/
public class TextAreaPainter_ScrollingVarFont extends TextAreaPainter {
/*
** Variables
*/
/*
** maximum text width
*/
protected int maximumTextWidth;
/*
** horizontal textscreen offset (pixels)
*/
protected int textOffset;
/*
** Constructor
*/
public TextAreaPainter_ScrollingVarFont(Font textfont, FontMetrics metrics, String text, Dimension size, Color[] colors) {
super(textfont,metrics, text, size,colors);
//also calculate the new visible line parts
textOffset=0;
calculateVisibleLineparts();
}
/*
** Text methods : overwrite setImage to just as well calculate the maximum width
*/
public void setImage(String text) {
super.setImage(text);
calculateMaximumWidth();
}
/*
** return Maximum width in pixels (with horizontal scrolling, we now have a maximum width and offset next to the viewport width)
*/
public int getMaximumWidth() {
return maximumTextWidth;
}
/*
** Offset calculations: (with horizontal scrolling, we now have a maximum width and offset next to the viewport width)
** Note that changing the text offset also changes the viewport
*/
public void setTextOffset(int offset) {
textOffset = offset;
calculateVisibleLineparts();
}
public void setOffset(int offsetx, int offsety) {
textOffset = offsetx;
lineOffset = offsety;
calculateVisibleLineparts();
}
public int getTextOffset() {
return textOffset;
}
public Point getOffset() {
return new Point(textOffset, lineOffset);
}
/*
** Calculate the maximum line length of the current text
*/
protected void calculateMaximumWidth() {
int currentwidth;
int start = textlineEnd[0];
maximumTextWidth=painterMetrics.charsWidth(textBuffer,0,start);
for(int i=1;i<textlineEnd.length;i++) {
currentwidth =painterMetrics.charsWidth(textBuffer, start, textlineEnd[i]-start);
if(currentwidth>maximumTextWidth) {
maximumTextWidth = currentwidth;
}
start = textlineEnd[i];
}
}
/*
** calculate lines, startChars and StopChars for given text, viewport and offset
*/
protected void calculateVisibleLineparts() {
//security
if(textBuffer.length<=0 || viewport.width<=0) {
return;
}
int start=0;
int currentwidth;
int viewoffset;
for(int i=0;i<textlineEnd.length;i++){
if (textOffset > 0) {
viewoffset = RudolphPeer.getChars(textOffset,start,textBuffer,painterMetrics)+1;
}
else {
viewoffset = textOffset; // so we use 'start' in next conditional
}
if (viewoffset > 0) {
viewTextOffset[i] = viewoffset;
}
else {
viewTextOffset[i] = start;
}
if(viewTextOffset[i]>=textlineEnd[i]) {
viewTextOffset[i] = textlineEnd[i];
viewTextLength[i] = 0;
}
else {
viewTextLength[i] = RudolphPeer.getChars(viewport.width,viewTextOffset[i],textBuffer,painterMetrics);
if(viewTextLength[i]>=textlineEnd[i]) {
// ends inside viewport: length = line from offset to end
viewTextLength[i] = textlineEnd[i]-viewTextOffset[i];
}
else {
// visible part end not yet passed end of line=>subtract offset to get length
viewTextLength[i]-= viewTextOffset[i];
}
}
// for next line
start=textlineEnd[i];
}
}
/*
** screen position to position in displayed text and vice versa
** as base class, but we don't bother with the char offset anymore (calculated when painting)
** since Rectangle.height relates to abssolute positoin in the textbuffer, it is not affected by the offset
** => pointdata[0] : position of the selected character in the original text
** => pointdata[1] : line of the selected character on the screen
** => pointdata[2] : horizontal offset in pixels (or offset calculation value) of the selected character from the left side of the screen
** => pointdata[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) {
// calculated y deeper then last line => set to last line
pointdata[1]= textlineEnd.length-1;
}
// total chars in the buffer before the given position
pointdata[3]= RudolphPeer.getChars(RudolphTextAreaPeer.getTextPos(x), viewTextOffset[pointdata[1]], textBuffer,painterMetrics);
// Calculate back the offset in pixels to the end of the clicked character
try {
pointdata[2]= painterMetrics.charsWidth(textBuffer,viewTextOffset[pointdata[1]],pointdata[3]-viewTextOffset[pointdata[1]]) + textOffset;
}
catch(ArrayIndexOutOfBoundsException e) {
pointdata[2] = 0;
}
// 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
pointdata[0] = pointdata[3] + pointdata[1];
}
/*
** screen position to position in displayed text and vice versa
** as base class, but we don't bother with the char offset anymore (calculated when painting)
** since Rectangle.height relates to abssolute positoin in the textbuffer, it is not affected by the offset
** => pointdata[0] : position of the selected character in the original text
** => pointdata[1] : line of the selected character on the screen
** => pointdata[2] : horizontal offset in pixels (or offset calculation value) of the selected character from the left side of the screen
** => pointdata[3] : position of the selected character in the TextPainter's text buffer (the text without the \n line breaks)
*/
public void setScreenPosition(int pos, int[] pointdata) {
//security
if(viewport.width<=0 || viewport.height<=0 ||textlineEnd.length<=0 ) {
return;
}
if(pos<0) {
pointdata[0] = 0;
pointdata[1] = 0;
pointdata[3] = 0;
pointdata[2] = 0;
}
else if( textlineEnd.length <= 1 && pos >=textBuffer.length) {
//Only one line and we passed it
pointdata[0] = textBuffer.length;
pointdata[1] = 0;// first line, that's obvious
pointdata[2] = painterMetrics.charsWidth(textBuffer, 0, textBuffer.length);
pointdata[3] = textBuffer.length;
}
else if( pos >=(textBuffer.length+textlineEnd.length-1)) {
//passed the end of buffer
pointdata[0] = textBuffer.length+textlineEnd.length;
pointdata[1] = textlineEnd.length-1;
// width: total chars width from start of last screen line, over <length of last screen line> chars
pointdata[2] = painterMetrics.charsWidth(textBuffer, textlineEnd[pointdata[1]-1], textBuffer.length - textlineEnd[pointdata[1]-1]);
pointdata[3] = textBuffer.length;
}
else {
pointdata[0] = pos;
// calculate lines from text pos (NOT buffer pos):
// while text pos > # chars before end of current line
// ->look next line
// -> decrease pos by 1 \n character for the line break jumped
pointdata[1] = 0;
while(pos>textlineEnd[pointdata[1]]) {
pointdata[1]++;
pos--;
}
pointdata[3] = pos;
// offset in pixels calculated through FontMetrics.CharsWidth(buffer, start, length)
pointdata[2]=(pointdata[1]>0)? painterMetrics.charsWidth(textBuffer,textlineEnd[pointdata[1]-1],pos-textlineEnd[pointdata[1]-1]):
painterMetrics.charsWidth(textBuffer,0,pos);
}
}
/*
** char position in line, offset to pointdata :
** pointData[1]: line and pointData[2] offset(in chars) are given.
** Up to us to calculate the corresponding text position and buffer position
** special case: when offset== -1 calculate the end of the line
*/
public void setScreenPositionLine(int line, int offset, int[] pointdata) {
if(line<0) {
// set all to beginning of text (first line, first pos)
pointdata[0]=0;
pointdata[1]=0;
pointdata[2]=0;
pointdata[3]=0;
}
else if(line>=textlineEnd.length) {
// set all to end of text
pointdata[1]=textlineEnd.length-1;
pointdata[2]=(pointdata[1]>0)? painterMetrics.charsWidth(textBuffer, textlineEnd[pointdata[1]-1], textBuffer.length-textlineEnd[pointdata[1]-1]) :
painterMetrics.charsWidth(textBuffer, 0, textBuffer.length);
pointdata[3]=textBuffer.length;
pointdata[0]=pointdata[3]+pointdata[1];
}
else if(offset<0) {
pointdata[1]=line;
pointdata[3]=textlineEnd[line];
pointdata[2]=(line>0)? painterMetrics.charsWidth(textBuffer, textlineEnd[line-1], textlineEnd[line] - textlineEnd[line-1]):
painterMetrics.charsWidth(textBuffer, 0, textlineEnd[line]);
pointdata[0]=pointdata[3]+line;
}
else if(offset==0) {
//speedy form, no offset in pixels means no offset in chars
pointdata[3]=(line>0)?textlineEnd[line-1] : 0;
pointdata[2]=0;
pointdata[1]=line;
pointdata[0]=pointdata[3]+line;
}
else{
pointdata[1]=line;
pointdata[3]=(line>0)?RudolphPeer.getChars(offset, textlineEnd[line-1], textBuffer,painterMetrics):
RudolphPeer.getChars(offset, 0, textBuffer,painterMetrics);
if(pointdata[3]>textlineEnd[line]) {
pointdata[3]=textlineEnd[line];
pointdata[2]=(line>0)? painterMetrics.charsWidth(textBuffer, textlineEnd[line-1], textlineEnd[line] - textlineEnd[line-1]):
painterMetrics.charsWidth(textBuffer, 0, textlineEnd[line]);
}
else {
pointdata[2]=offset;
}
pointdata[0]=pointdata[3]+line;
}
}
/*
** new paint for selections: viewTextOffset and ViewTextLength take care of the lines to display, but we still have the text offset
** to subtract from the cursor and selection positions(in pixels)
** Moreover, since each line starts at the beginning of the screen with a whole character, we have to calculate the pixel offset
** for cursor and selections on the fly
*/
public void paint (int width, int height, int cursorline, int cursoroffset, int cursorscreenpos, Graphics g){
if(cursorline >= viewTextOffset.length) {
cursorline = viewTextOffset.length - 1;
}
int offset = viewTextOffset[cursorline];
if(cursoroffset >= offset && offset <= textBuffer.length && cursoroffset <= textBuffer.length) {
cursorscreenpos = painterMetrics.charsWidth(textBuffer, offset, cursoroffset - offset);
}
else {
wonka.vm.Etc.woempa(9, "set cursorscreenpos to -1");
wonka.vm.Etc.woempa(9, "cursoroffset: "+cursoroffset);
wonka.vm.Etc.woempa(9, "offset: "+offset);
wonka.vm.Etc.woempa(9, "textBuffer.length: "+textBuffer.length);
cursorscreenpos=-1;
}
//paint area with cursor
RudolphTextAreaPeer.paintTextArea( 0,0,width,height,
textBuffer, viewTextOffset, viewTextLength, lineOffset,
cursorline, cursorscreenpos,
painterFont, painterMetrics, textColors, g, drawCursor);
}
public void paint(int width, int height, int startline, int startbufferoffset, int startscreenpos,
int stopline, int stopbufferoffset, int stopscreenpos, Graphics g) {
// recalculate screen pos to new value using the buffer pos and the current buffer viewtextoffset
if(startbufferoffset>viewTextOffset[startline]){
int temp = startbufferoffset-viewTextOffset[startline];
if(temp > textBuffer.length - viewTextOffset[startline]) temp = textBuffer.length - viewTextOffset[startline];
startscreenpos = painterMetrics.charsWidth(textBuffer,viewTextOffset[startline],temp);
}
else{
startscreenpos=-1; // strictly startscreenpos-= textOffset, but any number smaller then 0 will do
}
if(stopbufferoffset>viewTextOffset[stopline]){
int temp = stopbufferoffset-viewTextOffset[stopline];
if(temp > textBuffer.length - viewTextOffset[stopline]) temp = textBuffer.length - viewTextOffset[stopline];
stopscreenpos = painterMetrics.charsWidth(textBuffer,viewTextOffset[stopline],temp);
}
else{
stopscreenpos=-1; // strictly startscreenpos-= textOffset, but any number smaller then 0 will do
}
//stopscreenpos = painterMetrics.charsWidth(textBuffer,viewTextOffset[stopline],stopbufferoffset-viewTextOffset[stopline]);
RudolphTextAreaPeer.paintTextArea(
0,0,width,height,
textBuffer,viewTextOffset,viewTextLength,lineOffset,
startline, startbufferoffset, startscreenpos,
stopline, stopbufferoffset, stopscreenpos,
painterFont, painterMetrics, textColors, g, drawCursor
);
}
}