diff --git a/src/kits/interface/BTextView/TextGapBuffer.h b/src/kits/interface/BTextView/TextGapBuffer.h index 2cdb3bc265..f85d0cb31b 100644 --- a/src/kits/interface/BTextView/TextGapBuffer.h +++ b/src/kits/interface/BTextView/TextGapBuffer.h @@ -23,6 +23,8 @@ // Author: Marc Flerackers (mflerackers@androme.be) // 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 $ * diff --git a/src/kits/interface/BTextView/TextView.cpp b/src/kits/interface/BTextView/TextView.cpp index 6f1d71535a..92d8b2ea5c 100644 --- a/src/kits/interface/BTextView/TextView.cpp +++ b/src/kits/interface/BTextView/TextView.cpp @@ -47,6 +47,7 @@ #include "StyleBuffer.h" #include "TextGapBuffer.h" #include "UndoBuffer.h" +#include "WidthBuffer.h" // Local Defines --------------------------------------------------------------- @@ -141,8 +142,12 @@ prop_list[] = { 0 } }; -sem_id BTextView::sWidthSem = B_BAD_SEM_ID; // Created/deleted by init/fini_interface_kit -int32 BTextView::sWidthAtom = 0; + +// 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, @@ -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) { @@ -2414,7 +2423,9 @@ 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); @@ -3042,7 +3053,7 @@ BTextView::InitiateDrag() dragRect = bounds & dragRect; DragMessage(drag, dragRect, dragHandler); - } + } } //------------------------------------------------------------------------------ bool @@ -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); diff --git a/src/kits/interface/BTextView/UndoBuffer.cpp b/src/kits/interface/BTextView/UndoBuffer.cpp index ecd2aba002..731d8a88e0 100644 --- a/src/kits/interface/BTextView/UndoBuffer.cpp +++ b/src/kits/interface/BTextView/UndoBuffer.cpp @@ -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: 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) { - //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(); + 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; + } +} \ No newline at end of file diff --git a/src/kits/interface/BTextView/UndoBuffer.h b/src/kits/interface/BTextView/UndoBuffer.h index 66c184cd9a..3a3f50bfc8 100644 --- a/src/kits/interface/BTextView/UndoBuffer.h +++ b/src/kits/interface/BTextView/UndoBuffer.h @@ -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 diff --git a/src/kits/interface/BTextView/WidthBuffer.cpp b/src/kits/interface/BTextView/WidthBuffer.cpp new file mode 100644 index 0000000000..cffb718705 --- /dev/null +++ b/src/kits/interface/BTextView/WidthBuffer.cpp @@ -0,0 +1,88 @@ +// A quick and dirty implementation of _BWidthBuffer_, needed to compile +// OpenTracker. We'll want to implement it correctly. + +#include + +#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 +} diff --git a/src/kits/interface/BTextView/WidthBuffer.h b/src/kits/interface/BTextView/WidthBuffer.h new file mode 100644 index 0000000000..a31ff3587b --- /dev/null +++ b/src/kits/interface/BTextView/WidthBuffer.h @@ -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