Some more work on the undo buffer. Added a quick and dirty implementation of WidthBuffer (it's needed by OpenTracker). We'll want to implement it correctly.

Multi-byte character insertion/deletion works now in TextView (thanks to Marc Flerackers)


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5135 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini
2003-10-24 10:12:35 +00:00
parent 3ec998df56
commit 76f8475798
6 changed files with 274 additions and 63 deletions
@@ -23,6 +23,8 @@
// Author: Marc Flerackers ([email protected])
// Description: Text storage used by BTextView
//------------------------------------------------------------------------------
#ifndef __TEXTGAPBUFFER_H
#define __TEXTGAPBUFFER_H
// Standard Includes -----------------------------------------------------------
@@ -92,6 +94,8 @@ _BTextGapBuffer_::operator[](long index) const
{
return (index < fGapIndex) ? fBuffer[index] : fBuffer[index + fGapCount];
}
#endif //__TEXTGAPBUFFER_H
/*
* $Log $
*
+43 -32
View File
@@ -47,6 +47,7 @@
#include "StyleBuffer.h"
#include "TextGapBuffer.h"
#include "UndoBuffer.h"
#include "WidthBuffer.h"
// Local Defines ---------------------------------------------------------------
@@ -141,9 +142,13 @@ prop_list[] =
{ 0 }
};
sem_id BTextView::sWidthSem = B_BAD_SEM_ID; // Created/deleted by init/fini_interface_kit
// Initialized/finalized by init/fini_interface_kit ?
_BWidthBuffer_* BTextView::sWidths = NULL;
sem_id BTextView::sWidthSem = B_BAD_SEM_ID;
int32 BTextView::sWidthAtom = 0;
//------------------------------------------------------------------------------
BTextView::BTextView(BRect frame, const char *name, BRect textRect,
uint32 resizeMask, uint32 flags)
@@ -285,6 +290,7 @@ BTextView::~BTextView()
delete fStyles;
delete fDisallowedChars;
delete fUndo;
delete fOffscreen;
}
//------------------------------------------------------------------------------
BArchivable *
@@ -387,7 +393,8 @@ BTextView::MouseDown(BPoint where)
BPoint loc;
ulong buttons;
GetMouse(&loc, &buttons);
// was the secondary button clicked?
// TODO: here we shouldn't check for B_SECONDARY_MOUSE_BUTTON,
// since dragging works also with the primary button.
if (buttons == B_SECONDARY_MOUSE_BUTTON) {
// was the click within the selection range?
if ((mouseOffset >= fSelStart) && (mouseOffset <= fSelEnd)) {
@@ -559,6 +566,7 @@ BTextView::WindowActivated(bool state)
void
BTextView::KeyDown(const char *bytes, int32 numBytes)
{
//TODO: Remove this and move it to specific key handlers ?
if (!fEditable)
return;
@@ -1072,7 +1080,7 @@ BTextView::Copy(BClipboard *clipboard)
fSelEnd - fSelStart);
int32 size;
if (IsStylable()) {
if (fStylable) {
text_run_array *runArray = RunArray(fSelStart, fSelEnd, &size);
clip->AddData("application/x-vnd.Be-text_run_array", B_MIME_TYPE,
runArray, size);
@@ -1099,7 +1107,7 @@ BTextView::Paste(BClipboard *clipboard)
text_run_array *runArray = NULL;
ssize_t runLen = 0;
if (IsStylable())
if (fStylable)
clip->FindData("application/x-vnd.Be-text_run_array", B_MIME_TYPE,
(const void **)&runArray, &runLen);
@@ -1458,10 +1466,10 @@ BTextView::OffsetAt(BPoint point) const
{
// should we even bother?
if (point.y >= fTextRect.bottom)
return (fText->Length());
return fText->Length();
else {
if (point.y < fTextRect.top)
return (0);
return 0;
}
int32 lineNum = LineAt(point);
@@ -1942,7 +1950,8 @@ BTextView::SetAlignment(alignment flag)
fAlignment = flag;
}
//------------------------------------------------------------------------------
alignment BTextView::Alignment() const
alignment
BTextView::Alignment() const
{
return fAlignment;
}
@@ -2004,6 +2013,8 @@ BTextView::DoesUndo() const
void
BTextView::HideTyping(bool enabled)
{
//TODO: Implement ?
//fText->SetPasswordMode(enabled);
}
//------------------------------------------------------------------------------
bool
@@ -2248,14 +2259,6 @@ BTextView::InitObject(BRect textRect, const BFont *initialFont,
void
BTextView::HandleBackspace()
{
if (fSelStart == fSelEnd) {
if (fSelStart == 0)
return;
else
fSelStart--;
}
else
Highlight(fSelStart, fSelEnd);
if (fUndo) {
_BTypingUndoBuffer_ *undoBuffer = dynamic_cast<_BTypingUndoBuffer_ *>(fUndo);
@@ -2266,6 +2269,14 @@ BTextView::HandleBackspace()
undoBuffer->BackwardErase();
}
if (fSelStart == fSelEnd) {
if (fSelStart == 0)
return;
else
fSelStart = PreviousInitialByte(fSelStart);
} else
Highlight(fSelStart, fSelEnd);
DeleteText(fSelStart, fSelEnd);
fSelEnd = fSelStart;
@@ -2354,15 +2365,6 @@ BTextView::HandleArrowKey(uint32 inArrowKey)
void
BTextView::HandleDelete()
{
if (fSelStart == fSelEnd) {
if (fSelEnd == fText->Length())
return;
else
fSelEnd = NextInitialByte(fSelEnd);
}
else
Highlight(fSelStart, fSelEnd);
if (fUndo) {
_BTypingUndoBuffer_ *undoBuffer = dynamic_cast<_BTypingUndoBuffer_ *>(fUndo);
if (!undoBuffer) {
@@ -2372,6 +2374,15 @@ BTextView::HandleDelete()
undoBuffer->ForwardErase();
}
if (fSelStart == fSelEnd) {
if (fSelEnd == fText->Length())
return;
else
fSelEnd = NextInitialByte(fSelEnd);
}
else
Highlight(fSelStart, fSelEnd);
DeleteText(fSelStart, fSelEnd);
fSelEnd = fSelStart;
@@ -2404,8 +2415,6 @@ BTextView::HandlePageKey(uint32 inPageKey)
void
BTextView::HandleAlphaKey(const char *bytes, int32 numBytes)
{
bool refresh = fSelStart != fText->Length();
if (fUndo) {
_BTypingUndoBuffer_ *undoBuffer = dynamic_cast<_BTypingUndoBuffer_ *>(fUndo);
if (!undoBuffer) {
@@ -2415,6 +2424,8 @@ BTextView::HandleAlphaKey(const char *bytes, int32 numBytes)
undoBuffer->InputCharacter(numBytes);
}
bool refresh = fSelStart != fText->Length();
if (fSelStart != fSelEnd) {
Highlight(fSelStart, fSelEnd);
DeleteText(fSelStart, fSelEnd);
@@ -2627,10 +2638,10 @@ BTextView::FindLineBreak(int32 fromOffset, float *outAscent,
offset = (offset < limit) ? offset + 1 : limit;
// iterate through the style runs
int32 length = offset;
int32 startOffset = fromOffset;
int32 length = offset;
int32 startOffset = fromOffset;
int32 numChars;
while ((numChars = fStyles->Iterate(startOffset, length, NULL, NULL, &ascent, &descent) != 0)) {
while ((numChars = fStyles->Iterate(startOffset, length, NULL, NULL, &ascent, &descent)) != 0) {
*outAscent = (ascent > *outAscent) ? ascent : *outAscent;
*outDescent = (descent > *outDescent) ? descent : *outDescent;
@@ -2775,7 +2786,7 @@ BTextView::StyledWidth(int32 fromOffset, int32 length, float *outAscent,
// iterate through the style runs
const BFont *font = NULL;
int32 numChars;
while ((numChars = fStyles->Iterate(fromOffset, length, &font, NULL, &ascent, &descent) != 0)) {
while ((numChars = fStyles->Iterate(fromOffset, length, &font, NULL, &ascent, &descent)) != 0) {
maxAscent = (ascent > maxAscent) ? ascent : maxAscent;
maxDescent = (descent > maxDescent) ? descent : maxDescent;
@@ -2884,7 +2895,7 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
const BFont *font = NULL;
const rgb_color *color = NULL;
int32 numChars;
while ((numChars = fStyles->Iterate(offset, length, &font, &color) != 0)) {
while ((numChars = fStyles->Iterate(offset, length, &font, &color)) != 0) {
SetFont(font);
SetHighColor(*color);
@@ -3077,7 +3088,7 @@ BTextView::MessageDropped(BMessage *inMessage, BPoint where, BPoint offset)
text_run_array *runArray = NULL;
ssize_t runLen = 0;
if (IsStylable())
if (fStylable)
inMessage->FindData("application/x-vnd.Be-text_run_array", B_MIME_TYPE,
(const void **)&runArray, &runLen);
+90 -27
View File
@@ -264,7 +264,8 @@ _BTypingUndoBuffer_::_BTypingUndoBuffer_(BTextView *textView)
_BUndoBuffer_(textView, B_UNDO_TYPING),
fTypedText(NULL),
fTypedStart(fStart),
fNumBytes(0)
fTypedEnd(fEnd),
fUndone(0)
{
}
@@ -278,14 +279,18 @@ _BTypingUndoBuffer_::~_BTypingUndoBuffer_()
void
_BTypingUndoBuffer_::UndoSelf(BClipboard *clipboard)
{
int32 len = fTypedEnd - fTypedStart;
free(fTypedText);
fTypedText = (char *)malloc(fNumBytes);
memcpy(fTypedText, fTextView->Text() + fTypedStart, fNumBytes);
fTypedText = NULL;
fTypedText = (char *)malloc(len);
memcpy(fTypedText, fTextView->Text() + fTypedStart, len);
fTextView->Select(fTypedStart, fTypedStart);
fTextView->Delete(fTypedStart, fTypedStart + fNumBytes);
fTextView->Delete(fTypedStart, fTypedEnd);
fTextView->Insert(fTextData, fTextLength);
fTextView->Select(fStart, fEnd);
fUndone++;
}
@@ -294,7 +299,8 @@ _BTypingUndoBuffer_::RedoSelf(BClipboard *clipboard)
{
fTextView->Select(fTypedStart, fTypedStart);
fTextView->Delete(fTypedStart, fTypedStart + fTextLength);
fTextView->Insert(fTypedText, fNumBytes);
fTextView->Insert(fTypedText, fTypedEnd - fTypedStart);
fUndone--;
}
@@ -304,22 +310,22 @@ _BTypingUndoBuffer_::InputCharacter(int32 len)
int32 start, end;
fTextView->GetSelection(&start, &end);
int32 currentPos = fTypedStart + fNumBytes;
if (start != currentPos)
if (start != fTypedEnd || end != fTypedEnd)
Reset();
fNumBytes += len;
fTypedEnd += len;
}
void
_BTypingUndoBuffer_::Reset()
{
printf("Reset\n");
free(fTextData);
fTextView->GetSelection(&fStart, &fEnd);
fTextLength = fEnd - fStart;
fTypedStart = fStart;
fNumBytes = 0;
fTypedEnd = fStart;
fTextData = (char *)malloc(fTextLength);
memcpy(fTextData, fTextView->Text() + fStart, fTextLength);
@@ -327,36 +333,93 @@ _BTypingUndoBuffer_::Reset()
free(fTypedText);
fTypedText = NULL;
fRedo = false;
fUndone = 0;
}
void
_BTypingUndoBuffer_::ForwardErase()
{
//TODO: Fix this. Currently, it just resets the
//undobuffer every time DELETE is pressed, while
//it should reset it just the first time it's pressed.
//Moreover, it doesn't work with multi-byte characters.
int32 start, end;
fTextView->GetSelection(&start, &end);
int32 currentPos = fTypedStart + fNumBytes;
if (start != currentPos)
Reset();
// TODO: This isn't completely safe and it's even slower than parsing byte
// by byte, but I'll change it later.
static inline int32
UTF8_char_len(uchar c)
{
return ((0xE5000000 >> ((c >> 3) & 0x1E)) & 3) + 1;
}
void
_BTypingUndoBuffer_::BackwardErase()
{
//TODO: Fix this. Currently, it just resets the
//undobuffer every time BACKSPACE is pressed, while
//it should reset it just the first time it's pressed.
//Moreover, it doesn't work with multi-byte characters.
int32 start, end;
fTextView->GetSelection(&start, &end);
int32 currentPos = fTypedStart + fNumBytes;
if (start != currentPos)
int32 charLen = UTF8_char_len(fTextView->ByteAt(start - 1));
printf("Char Len: %d\n", charLen);
if (start != fTypedEnd || end != fTypedEnd) {
Reset();
// if we've got a selection, we're already done
if (start != end)
return;
}
char *buffer = (char *)malloc(fTextLength + charLen);
memcpy(buffer + charLen, fTextData, fTextLength);
fTypedStart = start - charLen;
start = fTypedStart;
for (int32 x = 0; x < charLen; x++)
buffer[x] = fTextView->ByteAt(start + x);
free(fTextData);
fTextData = buffer;
fTextLength += charLen;
fTypedEnd -= charLen;
}
void
_BTypingUndoBuffer_::ForwardErase()
{
int32 start, end;
fTextView->GetSelection(&start, &end);
int32 charLen = UTF8_char_len(fTextView->ByteAt(start));
printf("Char Len: %d\n", charLen);
if (start != fTypedEnd || end != fTypedEnd || fUndone > 0) {
Reset();
// if we've got a selection, we're already done
if (fStart == fEnd) {
free(fTextData);
fTextLength = charLen;
fTextData = (char *)malloc(fTextLength);
// store the erased character
for (int32 x = 0; x < charLen; x++)
fTextData[x] = fTextView->ByteAt(start + x);
}
} else {
// Here we need to store the erased text, so we get the text that it's
// already in the buffer, and we add the erased character.
// a realloc + memmove would maybe be cleaner, but that way we spare a
// copy (malloc + memcpy vs realloc + memmove).
int32 newLength = fTextLength + charLen;
char *buffer = (char *)malloc(newLength);
// copy the already stored data
memcpy(buffer, fTextData, fTextLength);
if (fTextLength < newLength) {
// store the erased character
for (int32 x = 0; x < charLen; x++)
buffer[fTextLength] = fTextView->ByteAt(start + x);
}
fTextLength = newLength;
free(fTextData);
fTextData = buffer;
}
}
+3 -1
View File
@@ -56,6 +56,7 @@ protected:
bool fRedo;
private:
undo_state fState;
};
@@ -137,7 +138,8 @@ private:
char *fTypedText;
int32 fTypedStart;
int32 fNumBytes;
int32 fTypedEnd;
int32 fUndone;
};
#endif //__UNDOBUFFER_H
@@ -0,0 +1,88 @@
// A quick and dirty implementation of _BWidthBuffer_, needed to compile
// OpenTracker. We'll want to implement it correctly.
#include <Font.h>
#include "WidthBuffer.h"
_BWidthBuffer_::_BWidthBuffer_()
{
//TODO: Implement
}
_BWidthBuffer_::~_BWidthBuffer_()
{
//TODO: Implement
}
float
_BWidthBuffer_::StringWidth(const char *inText, int32 fromOffset, int32 length,
const BFont *inStyle)
{
// TODO: Should use local hashed items
return inStyle->StringWidth(inText + fromOffset, length);
}
float
_BWidthBuffer_::StringWidth(_BTextGapBuffer_ &inBuffer, int32 fromOffset, int32 length,
const BFont *inStyle)
{
return inStyle->StringWidth(inBuffer.Text() + fromOffset, length);
}
bool
_BWidthBuffer_::FindTable(const BFont *inStyle, int32 *outIndex)
{
float fontSize = inStyle->Size();
int32 fontCode = inStyle->FamilyAndStyle();
for (int32 i = 0; i < fItemCount; i++) {
#if B_BEOS_VERSION_DANO
if (*inStyle == fBuffer[i].font) {
#else
if (fontSize == fBuffer[i].fontSize && fontCode == fBuffer[i].fontCode) {
#endif
*outIndex = i;
return true;
}
}
*outIndex = -1;
return false;
}
int32
_BWidthBuffer_::InsertTable(const BFont *font)
{
//TODO: Implement
return B_ERROR;
}
bool
_BWidthBuffer_::GetEscapement(uint32 code, int32 index, float *escapement)
{
//TODO: Implement
return false;
}
uint32
_BWidthBuffer_::Hash(uint32 val)
{
//TODO: Implement
return B_ERROR;
}
void
_BWidthBuffer_::HashEscapements(const char *inText, int32 numChars, int32,
int32, const BFont *inStyle)
{
//TODO: Implement
}
@@ -0,0 +1,43 @@
#ifndef __WIDTHBUFFER_H
#define __WIDTHBUFFER_H
#include "TextGapBuffer.h"
#include "TextViewSupportBuffer.h"
struct _width_table_ {
#if B_BEOS_VERSION_DANO
BFont font; // corresponding font
#else
int32 fontCode; // font code
float fontSize; // font size
#endif
int32 hashCount; // number of hashed items
int32 tableCount; // size of table
void *widths; // width table
};
class _BWidthBuffer_ : public _BTextViewSupportBuffer_<_width_table_> {
public:
_BWidthBuffer_();
virtual ~_BWidthBuffer_();
float StringWidth(const char *inText, int32 fromOffset, int32 length,
const BFont *inStyle);
float StringWidth(_BTextGapBuffer_ &, int32 fromOffset, int32 length,
const BFont *inStyle);
private:
bool FindTable(const BFont *font, int32 *outIndex);
int32 InsertTable(const BFont *font);
bool GetEscapement(uint32, int32, float *);
void HashEscapements(const char *, int32, int32, int32, const BFont *);
uint32 Hash(uint32);
void CCheck();
};
#endif // __WIDTHBUFFER_H