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:
@@ -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 $
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user