- Fixed every Styling issue (at least the ones exposed by StyledEdit). Setting fonts works now

- Cleaned up PageUp/Down handling code
- Now setups undo in Clear()
- Alignment now partially works
- Fixed some visual artifacts which could've showed up during typing with an input method
- Added a "known bugs" section


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9096 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini 2004-09-29 07:18:10 +00:00
parent 9ade9e873d
commit 70751f7bfc
2 changed files with 126 additions and 100 deletions

View File

@ -104,7 +104,7 @@ _BStyleRecordBuffer_::InsertRecord(const BFont *inFont,
// look for style in buffer
if (MatchRecord(inFont, inColor, &index))
return (index);
return index;
// style not found, add it
font_height fh;
@ -157,9 +157,7 @@ _BStyleRecordBuffer_::MatchRecord(const BFont *inFont,
const rgb_color *inColor, int32 *outIndex)
{
for (int32 i = 0; i < fItemCount; i++) {
if ( (inFont->Size() == fBuffer[i].style.font.Size()) &&
(inFont->Shear() == fBuffer[i].style.font.Shear()) &&
(inFont->Face() == fBuffer[i].style.font.Face()) &&
if ( (*inFont == fBuffer[i].style.font) &&
(inColor->red == fBuffer[i].style.color.red) &&
(inColor->green == fBuffer[i].style.color.green) &&
(inColor->blue == fBuffer[i].style.color.blue) &&
@ -289,8 +287,7 @@ _BStyleBuffer_::SetStyleRange(int32 fromOffset, int32 toOffset,
fStyleRunDesc.InsertDesc(&newDesc, runIndex + 1);
fStyleRecord.CommitRecord(newDesc.index);
runIndex++;
}
else {
} else {
fStyleRunDesc[runIndex]->index = styleIndex;
fStyleRecord.CommitRecord(styleIndex);
}
@ -348,6 +345,9 @@ _BStyleBuffer_::GetStyleRange(int32 startOffset, int32 endOffset) const
result = (STEStyleRangePtr)malloc(sizeof(int32) +
(sizeof(STEStyleRun) * numStyles));
if (!result)
return NULL;
result->count = numStyles;
STEStyleRunPtr run = &result->runs[0];
for (int32 index = 0; index < numStyles; index++) {

View File

@ -26,7 +26,7 @@
// Description: BTextView displays and manages styled text.
//------------------------------------------------------------------------------
// TODO:
// TODOs:
// - Finish documenting this class
// - Consider using BObjectList instead of BList
// for disallowed charachters (it would remove a lot of reinterpret_casts)
@ -34,6 +34,12 @@
// - Check for correctness and possible optimizations the calls to Refresh(),
// to refresh only changed parts of text (currently we often redraw the whole text)
// Known Bugs:
// - PointAt(), OffsetAt(), and possibly some other functions don't work right yet
// when alignment is different than B_ALIGN_LEFT.
// - visual artifacts appears when you highlight some text which spans between
// multiple lines and with mixed sizes/styles (could be something in GetTextRegion())
// Standard Includes -----------------------------------------------------------
#include <cstdlib>
#include <cstdio>
@ -1093,7 +1099,6 @@ BTextView::SetText(BFile *inFile, int32 inOffset, int32 inLength,
fStyles->BumpOffset(inLength, fStyles->OffsetToRun(inOffset - 1) + 1);
if (inRuns != NULL)
//SetStyleRange(inOffset, inOffset + inLength, inStyles, false);
SetRunArray(inOffset, inOffset + inLength, inRuns);
else {
// apply nullStyle to inserted text
@ -1186,37 +1191,7 @@ void
BTextView::Delete()
{
CALLED();
CancelInputMethod();
// anything to delete?
if (fSelStart == fSelEnd)
return;
// hide the caret/unhilite the selection
if (fActive) {
if (fSelStart != fSelEnd)
Highlight(fSelStart, fSelEnd);
else {
if (fCaretVisible)
InvertCaret();
}
}
// remove data from buffer
DeleteText(fSelStart, fSelEnd);
// collapse the selection
fClickOffset = fSelEnd = fSelStart;
// recalc line breaks and draw what's left
Refresh(fSelStart, fSelEnd, true, true);
// draw the caret
if (fActive) {
if (!fCaretVisible)
InvertCaret();
}
Delete(fSelStart, fSelEnd);
}
@ -1446,6 +1421,9 @@ void
BTextView::Clear()
{
CALLED();
delete fUndo;
fUndo = new _BClearUndoBuffer_(this);
Delete();
}
@ -1491,6 +1469,8 @@ BTextView::Select(int32 startOffset, int32 endOffset)
if (!fSelectable)
return;
CancelInputMethod();
// a negative selection?
if (startOffset > endOffset)
return;
@ -1802,6 +1782,10 @@ BTextView::LineAt(BPoint point) const
BPoint
BTextView::PointAt(int32 inOffset, float *outHeight) const
{
// TODO: when alignment is != than B_ALIGN_LEFT,
// this function's still a bit broken.
// Cleanup.
CALLED();
BPoint result;
int32 textLength = fText->Length();
@ -1810,6 +1794,7 @@ BTextView::PointAt(int32 inOffset, float *outHeight) const
float height = 0;
result.x = 0.0;
result.y = line->origin + fTextRect.top;
// Handle the case where there is only one line
@ -1843,7 +1828,9 @@ BTextView::PointAt(int32 inOffset, float *outHeight) const
do {
foundTab = fText->FindChar(B_TAB, offset, &numChars);
result.x += StyledWidth(offset, numChars);
float width = StyledWidth(offset, numChars);
result.x += width;
if (foundTab) {
result.x += ActualTabWidth(result.x);
@ -1857,6 +1844,13 @@ BTextView::PointAt(int32 inOffset, float *outHeight) const
}
}
if (fAlignment != B_ALIGN_LEFT) {
float modifier = fTextRect.right - StyledWidth(line->offset,
(line + 1)->offset - line->offset);
if (fAlignment == B_ALIGN_CENTER)
modifier /= 2;
result.x += modifier;
}
// convert from text rect coordinates
result.x += fTextRect.left - 1.0;
@ -1877,6 +1871,9 @@ BTextView::PointAt(int32 inOffset, float *outHeight) const
int32
BTextView::OffsetAt(BPoint point) const
{
// TODO: When alignment is different than B_ALIGN_LEFT,
// this function is still broken.
CALLED();
// should we even bother?
if (point.y >= fTextRect.bottom)
@ -1898,7 +1895,7 @@ BTextView::OffsetAt(BPoint point) const
// convert to text rect coordinates
point.x -= fTextRect.left;
point.x = (point.x < 0.0) ? 0.0 : point.x;
point.x = max_c(point.x, 0.0);
// do a pseudo-binary search of the character widths on the line
// that PixelToLine() gave us
@ -2118,6 +2115,9 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
BPoint startPt = PointAt(startOffset, &startLineHeight);
BPoint endPt = PointAt(endOffset, &endLineHeight);
startLineHeight = ceil(startLineHeight);
endLineHeight = ceil(endLineHeight);
BRect selRect;
if (startPt.y == endPt.y) {
@ -2127,7 +2127,6 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
selRect.right = endPt.x - 1.0;
selRect.bottom = endPt.y + endLineHeight - 1.0;
outRegion->Include(selRect);
} else {
// more than one line in the specified offset range
selRect.left = max_c(startPt.x, fTextRect.left);
@ -2139,7 +2138,7 @@ BTextView::GetTextRegion(int32 startOffset, int32 endOffset,
if (startPt.y + startLineHeight < endPt.y) {
// more than two lines in the range
selRect.left = fTextRect.left;
selRect.top = startPt.y + startLineHeight + 1.0;
selRect.top = startPt.y + startLineHeight;
selRect.right = fTextRect.right;
selRect.bottom = endPt.y - 1.0;
outRegion->Include(selRect);
@ -2353,8 +2352,6 @@ BTextView::SetWordWrap(bool wrap)
if (wrap == fWrap)
return;
fWrap = wrap;
if (Window() != NULL) {
if (fActive) {
// hide the caret, unhilite the selection
@ -2366,6 +2363,7 @@ BTextView::SetWordWrap(bool wrap)
}
}
fWrap = wrap;
Refresh(0, fText->Length(), true, true);
if (fActive) {
@ -2447,7 +2445,10 @@ BTextView::SetAlignment(alignment flag)
CALLED();
// Do a reality check
if (fAlignment != flag && flag >= 0 && flag <= 2) {
if (fAlignment != flag &&
(flag == B_ALIGN_LEFT ||
flag == B_ALIGN_RIGHT ||
flag == B_ALIGN_CENTER)) {
fAlignment = flag;
// After setting new alignment, update the view/window
@ -3067,18 +3068,23 @@ BTextView::HandlePageKey(uint32 inPageKey)
STELinePtr line = NULL;
int32 start = fSelStart, end = fSelEnd;
switch (inPageKey) {
case B_HOME:
line = (*fLines)[CurrentLine()];
fClickOffset = line->offset;
ScrollToOffset(fClickOffset);
if (shiftDown) {
if (fClickOffset <= fSelStart)
Select(fClickOffset, fSelEnd);
else
Select(fSelStart, fClickOffset);
if (fClickOffset <= fSelStart) {
start = fClickOffset;
end = fSelEnd;
} else {
start = fSelStart;
end = fClickOffset;
}
} else
Select(fClickOffset, fClickOffset);
start = end = fClickOffset;
break;
case B_END:
@ -3089,63 +3095,74 @@ BTextView::HandlePageKey(uint32 inPageKey)
line = (*fLines)[CurrentLine() + 1];
fClickOffset = PreviousInitialByte(line->offset);
} else {
// This check if needed to avoid moving the cursor
// when the cursor is on the last line, and that line
// is empty
if (fClickOffset != fText->Length()) {
fClickOffset = fText->Length();
if (ByteAt(fClickOffset - 1) == B_ENTER)
fClickOffset--;
}
ScrollToOffset(fClickOffset);
}
if (shiftDown) {
if (fClickOffset >= fSelEnd)
Select(fSelStart, fClickOffset);
else
Select(fClickOffset, fSelEnd);
if (fClickOffset >= fSelEnd) {
start = fSelStart;
end = fClickOffset;
} else {
start = fClickOffset;
end = fSelEnd;
}
} else
Select(fClickOffset, fClickOffset);
start = end = fClickOffset;
break;
// TODO: Clean up this mess
case B_PAGE_UP:
{
int32 currentOffset = OffsetAt(fClickOffset);
float delta = Bounds().Height();
BPoint currentPos = PointAt(fClickOffset);
if (ScrollBar(B_VERTICAL) != NULL)
ScrollBar(B_VERTICAL)->SetValue(ScrollBar(B_VERTICAL)->Value() - delta);
fClickOffset = OffsetAt(LineAt(PointAt(currentOffset - delta)));
currentPos.y -= Bounds().Height();
fClickOffset = OffsetAt(LineAt(currentPos));
if (shiftDown) {
if (fClickOffset <= fSelStart)
Select(fClickOffset, fSelEnd);
else
Select(fSelStart, fClickOffset);
if (fClickOffset <= fSelStart) {
start = fClickOffset;
end = fSelEnd;
} else {
start = fSelStart;
end = fClickOffset;
}
} else
Select(fClickOffset, fClickOffset);
start = end = fClickOffset;
break;
}
case B_PAGE_DOWN:
{
int32 currentOffset = OffsetAt(fClickOffset);
float delta = Bounds().Height();
BPoint currentPos = PointAt(fClickOffset);
if (ScrollBar(B_VERTICAL) != NULL)
ScrollBar(B_VERTICAL)->SetValue(ScrollBar(B_VERTICAL)->Value() + delta);
fClickOffset = OffsetAt(LineAt(PointAt(currentOffset + delta)) + 1);
currentPos.y += Bounds().Height();
fClickOffset = OffsetAt(LineAt(currentPos) + 1);
if (shiftDown) {
if (fClickOffset >= fSelEnd)
Select(fSelStart, fClickOffset);
else
Select(fClickOffset, fSelEnd);
if (fClickOffset >= fSelEnd) {
start = fSelStart;
end = fClickOffset;
} else {
start = fClickOffset;
end = fSelEnd;
}
} else
Select(fClickOffset, fClickOffset);
start = end = fClickOffset;
break;
}
}
ScrollToOffset(fClickOffset);
Select(start, end);
}
@ -3647,14 +3664,21 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
eraseRect = clipRect;
}
float startLeft = fTextRect.left;
for (long i = startLine; i <= endLine; i++) {
long length = (line + 1)->offset - line->offset;
// DrawString() chokes if you draw a newline
if ((*fText)[(line + 1)->offset - 1] == '\n')
length--;
MovePenTo(fTextRect.left, line->origin + line->ascent + fTextRect.top);
if (fAlignment != B_ALIGN_LEFT) {
// B_ALIGN_RIGHT
startLeft = (fTextRect.right - StyledWidth(line->offset, length));
if (fAlignment == B_ALIGN_CENTER)
startLeft /= 2;
}
MovePenTo(startLeft, line->origin + line->ascent + fTextRect.top);
if (erase && i >= startEraseLine) {
eraseRect.top = line->origin + fTextRect.top;
@ -3761,7 +3785,7 @@ BTextView::DrawCaret(int32 offset)
//STELinePtr line = (*fLines)[lineNum];
float lineHeight;
BPoint caretPoint = PointAt(offset, &lineHeight);
caretPoint.x = (caretPoint.x > fTextRect.right) ? fTextRect.right : caretPoint.x;
caretPoint.x = min_c(caretPoint.x, fTextRect.right);
BRect caretRect;
caretRect.left = caretRect.right = caretPoint.x;
@ -4417,6 +4441,8 @@ BTextView::CancelInputMethod()
delete fInline;
fInline = NULL;
Refresh(0, fText->Length(), true, false);
}