void WrappingTextView::ResetTextRect()
{
	BRect bounds = Bounds();
	BRect textRect = bounds;
	textRect.left = 4.0;
	textRect.top = m_vertical_offset + 4.0f;
	if (m_fixed_width)
		textRect.right = 8.0f + StringWidth( "0") * float(m_fixed_width);
	else
		textRect.right -= 4.0f;
	textRect.bottom -= 4.0f;
	SetTextRect(textRect);
	// we have to readjust the scrollbar-proportion, since
	// the BTextView doesn't do it correctly when we have
	// fooled in a vertical_offset:
	float small, big;
	BScrollBar* bar = ScrollBar( B_VERTICAL);
	if (!bar) 	return;
	bar->GetSteps( &small, &big);
	float height = TextHeight( 0, TextLength());
	if (height+m_vertical_offset)
		bar->SetProportion( MIN( 1.0f, big/(height+m_vertical_offset)));
	else 
		bar->SetProportion( 1.0f);

	if (BeamOnDano) {
		// circumvent a special feature/bug in Zeta with respect to 
		// the scrollbar not always calling ValueChanged() on a click.
		// Seemingly, changing the value twice hides the bug:
		bar->SetValue(1);
		bar->SetValue(0);
	}

	bar = ScrollBar( B_HORIZONTAL);
	if (!bar) 	return;
	float width = bounds.Width();
	float maxWidth = MAX( width, textRect.right);
	int numChildren = IsEditable() ? 0 : CountChildren();
	for( int i=0; i<numChildren; ++i) {
		float w = ChildAt( i)->Frame().Width();
		if (w > maxWidth)
			maxWidth = w;
	}
	bar->SetSteps( width/10, width);
	bar->SetRange( 0, MAX(0, maxWidth-width));
	bar->SetProportion( MIN( 1.0f, width/maxWidth));
}
void WrappingTextView::KeyDown(const char *bytes, int32 numBytes) 
{ 
	if (IsEditable() && numBytes==1) {
		m_last_key_was_del = (bytes[0]==B_DELETE);
		switch( bytes[0]) {
			case B_RIGHT_ARROW: {
				// implement word-wise movement:
				int32 mods = Window()->CurrentMessage()->FindInt32("modifiers");
				if (mods & (B_LEFT_CONTROL_KEY | B_RIGHT_OPTION_KEY)) {
					int32 len=TextLength();
					int32 startPos, endPos;
					GetSelection( &startPos, &endPos);
					if (endPos==len)
						break;
					if (startPos==endPos && (mods & B_SHIFT_KEY))
						m_selection_start=B_RIGHT_ARROW;
					int32 wordStart, wordEnd;
					if (mods & B_SHIFT_KEY && m_selection_start==B_LEFT_ARROW) {
						do {
							FindWord( startPos, &wordStart, &wordEnd);
							if (wordEnd > wordStart+1)
								break;
							if (wordEnd == wordStart+1 && ByteAt( wordStart)!=' ')
								break;
						} while( ++startPos < len);
						Select( MIN(endPos, wordEnd), endPos);
					} else {
						do {
							FindWord( endPos, &wordStart, &wordEnd);
							if (wordEnd > wordStart+1)
								break;
							if (wordEnd == wordStart+1 && ByteAt( wordStart)!=' ')
								break;
						} while( ++endPos < len);
						if (mods & B_SHIFT_KEY) {
							Select( startPos, wordEnd);
						} else
							Select( wordEnd, wordEnd);
					}
					ScrollToSelection();
				} else
					inherited::KeyDown( bytes, numBytes);
				break;
			}
			case B_LEFT_ARROW: {
				// implement word-wise movement:
				int32 mods = Window()->CurrentMessage()->FindInt32("modifiers");
				if (mods & (B_LEFT_CONTROL_KEY | B_RIGHT_OPTION_KEY)) {
					int32 startPos, endPos;
					GetSelection( &startPos, &endPos);
					if (!startPos)
						break;
					if (startPos==endPos && (mods & B_SHIFT_KEY))
						m_selection_start=B_LEFT_ARROW;
					int32 wordStart, wordEnd;
					if (mods & B_SHIFT_KEY && m_selection_start==B_RIGHT_ARROW) {
						--endPos;
						do {
							FindWord( endPos, &wordStart, &wordEnd);
							if (wordEnd > wordStart+1)
								break;
							if (wordEnd == wordStart+1 && ByteAt( wordStart)!=' ')
								break;
						} while( --endPos > 0);
						Select( startPos, MAX( startPos, wordStart));
					} else {
						--startPos;
						do {
							FindWord( startPos, &wordStart, &wordEnd);
							if (wordEnd > wordStart+1)
								break;
							if (wordEnd == wordStart+1 && ByteAt( wordStart)!=' ')
								break;
						} while( --startPos > 0);
						if (mods & B_SHIFT_KEY)
							Select( wordStart, endPos);
						else
							Select( wordStart, wordStart);
					}
					ScrollToSelection();
				} else
					inherited::KeyDown( bytes, numBytes);
				break;
			}
			default:
				inherited::KeyDown( bytes, numBytes);
				break;
		}
	} else if ( numBytes == 1 ) {
		// in read-only mode, we use cursor-keys to move scrollbar, and
		// we remap HOME / END to the vertical scrollbar (not the horizontal,
		// which is default).
		switch( bytes[0]) {
			case B_PAGE_UP:
			case B_PAGE_DOWN:
			case B_UP_ARROW:
			case B_DOWN_ARROW:
			case B_HOME: 
			case B_END: {
				// move vertical scrollbar:
				float min, max, smallStep, bigStep, value;
				BScrollBar* bar = ScrollBar( B_VERTICAL);
				if (!bar) 	return;
				bar->GetRange( &min, &max);
				bar->GetSteps( &smallStep, &bigStep);
				value = bar->Value();
				if (bytes[0] == B_UP_ARROW) {
					value = MAX( value-smallStep, min);
				} else if (bytes[0] == B_DOWN_ARROW) {
					value = MIN( value+smallStep, max);
				} else if (bytes[0] == B_PAGE_UP) {
					value = MAX( value-bigStep, min);
				} else if (bytes[0] == B_PAGE_DOWN) {
					value = MIN( value+bigStep, max);
				} else if (bytes[0] == B_HOME) {
					value = min;
				} else if (bytes[0] == B_END) {
					value = max;
				}
				bar->SetValue( value);
				break;
			}
			default:
				BTextView::KeyDown( bytes, numBytes);
				break;
		}
	} else
		inherited::KeyDown( bytes, numBytes);
}