diff --git a/src/kits/interface/BTextView/InlineInput.cpp b/src/kits/interface/BTextView/InlineInput.cpp index d02eec26a5..66e1363be1 100644 --- a/src/kits/interface/BTextView/InlineInput.cpp +++ b/src/kits/interface/BTextView/InlineInput.cpp @@ -23,6 +23,11 @@ // Author: Stefano Ceccherini (burton666@libero.it) // Description: Helper class to handle input method requests //------------------------------------------------------------------------------ + +// TODO: he bebook says we should highlight in blue/red different "clauses". +// Though it looks like what really matters is the "selection" field in +// the BMessage sent by the input method addon. Have I missed something ? + #include "InlineInput.h" #include @@ -43,6 +48,8 @@ _BInlineInput_::_BInlineInput_(BMessenger messenger) fActive(false), fOffset(0), fLength(0), + fSelectionOffset(0), + fSelectionLength(0), fNumClauses(0), fClauses(NULL) { @@ -120,6 +127,34 @@ _BInlineInput_::SetOffset(int32 offset) } +int32 +_BInlineInput_::SelectionLength() const +{ + return fSelectionLength; +} + + +void +_BInlineInput_::SetSelectionLength(int32 length) +{ + fSelectionLength = length; +} + + +int32 +_BInlineInput_::SelectionOffset() const +{ + return fSelectionOffset; +} + + +void +_BInlineInput_::SetSelectionOffset(int32 offset) +{ + fSelectionOffset = offset; +} + + /*! \brief Adds a clause (see "The Input Server" sez. for details). \param start The offset into the string where the clause starts. \param end The offset into the string where the clause finishes. @@ -155,7 +190,14 @@ _BInlineInput_::GetClause(int32 index, int32 *start, int32 *end) const return result; } - + +int32 +_BInlineInput_::CountClauses() const +{ + return fNumClauses; +} + + /*! \brief Deletes any added clause. */ void diff --git a/src/kits/interface/BTextView/InlineInput.h b/src/kits/interface/BTextView/InlineInput.h index 8ec630a2c5..3b5b850c06 100644 --- a/src/kits/interface/BTextView/InlineInput.h +++ b/src/kits/interface/BTextView/InlineInput.h @@ -44,9 +44,16 @@ public: int32 Offset() const; void SetOffset(int32 offset); + + int32 SelectionLength() const; + void SetSelectionLength(int32); + + int32 SelectionOffset() const; + void SetSelectionOffset(int32 offset); void AddClause(int32, int32); bool GetClause(int32 index, int32 *start, int32 *end) const; + int32 CountClauses() const; void ResetClauses(); @@ -58,6 +65,9 @@ private: int32 fOffset; int32 fLength; + int32 fSelectionOffset; + int32 fSelectionLength; + int32 fNumClauses; clause *fClauses; }; diff --git a/src/kits/interface/BTextView/TextView.cpp b/src/kits/interface/BTextView/TextView.cpp index cd9357c26b..cda705a79b 100644 --- a/src/kits/interface/BTextView/TextView.cpp +++ b/src/kits/interface/BTextView/TextView.cpp @@ -127,7 +127,9 @@ sem_id BTextView::sWidthSem = B_BAD_SEM_ID; int32 BTextView::sWidthAtom = 0; #endif - +const static rgb_color kBlueInputColor = { 152, 203, 255 }; +const static rgb_color kRedInputColor = { 255, 152, 152 }; + static property_info sPropertyList[] = { { @@ -457,7 +459,8 @@ BTextView::MouseDown(BPoint where) if (fCaretVisible) InvertCaret(); - int32 mouseOffset = OffsetAt(where); + int32 oldOffset = fClickOffset; + fClickOffset = OffsetAt(where); bool shiftDown = modifiers() & B_SHIFT_KEY; // TODO: Asynchronous mouse tracking @@ -471,7 +474,7 @@ BTextView::MouseDown(BPoint where) // 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) { + if (fClickOffset >= fSelStart && fClickOffset <= fSelEnd) { InitiateDrag(); return; } @@ -492,7 +495,7 @@ BTextView::MouseDown(BPoint where) // is this a double/triple click, or is it a new click? if (clickSpeed > (system_time() - fClickTime) && - mouseOffset == fClickOffset ) { + oldOffset == fClickOffset ) { if (fClickCount > 1) { // triple click fClickCount = 0; @@ -504,12 +507,11 @@ BTextView::MouseDown(BPoint where) } } else { // new click - fClickOffset = mouseOffset; fClickCount = 1; fClickTime = system_time(); if (!shiftDown) { - Select(mouseOffset, mouseOffset); + Select(fClickOffset, fClickOffset); if (fEditable) InvertCaret(); } @@ -522,15 +524,15 @@ BTextView::MouseDown(BPoint where) // track the mouse while it's down long start = 0; long end = 0; - long anchor = (mouseOffset > fSelStart) ? fSelStart : fSelEnd; + long anchor = (fClickOffset > fSelStart) ? fSelStart : fSelEnd; BPoint curMouse = where; ulong buttons = 0; do { - if (mouseOffset > anchor) { + if (fClickOffset > anchor) { start = anchor; - end = mouseOffset; + end = fClickOffset; } else { - start = mouseOffset; + start = fClickOffset; end = anchor; } @@ -543,7 +545,7 @@ BTextView::MouseDown(BPoint where) case 2: // double click, select word by word - FindWord(mouseOffset, &start, &end); + FindWord(fClickOffset, &start, &end); break; default: @@ -552,7 +554,7 @@ BTextView::MouseDown(BPoint where) } if (shiftDown) { - if (mouseOffset > anchor) + if (fClickOffset > anchor) start = anchor; else end = anchor; @@ -590,7 +592,7 @@ BTextView::MouseDown(BPoint where) snooze(30000); GetMouse(&curMouse, &buttons); - mouseOffset = OffsetAt(curMouse); + fClickOffset = OffsetAt(curMouse); } while (buttons != 0); } @@ -2099,7 +2101,8 @@ BTextView::TextHeight(int32 startLine, int32 endLine) const if (endLine == numLines - 1 && (*fText)[fText->Length() - 1] == '\n') height += (*fLines)[endLine + 1]->origin - (*fLines)[endLine]->origin; - + height = ceil(height); + return height; } @@ -2952,12 +2955,15 @@ BTextView::HandleArrowKey(uint32 inArrowKey) case B_LEFT_ARROW: if (fClickOffset > 0) fClickOffset = PreviousInitialByte(fClickOffset); - + else if (shiftDown) + return; + if (shiftDown) { if (fClickOffset >= fSelStart) selEnd = fClickOffset; else - selStart = fClickOffset; + selStart = fClickOffset; + } else selStart = selEnd = fClickOffset; @@ -2967,7 +2973,9 @@ BTextView::HandleArrowKey(uint32 inArrowKey) case B_RIGHT_ARROW: if (fClickOffset < fText->Length()) fClickOffset = NextInitialByte(fClickOffset); - + else if (shiftDown) + return; + if (shiftDown) { if (fClickOffset <= fSelEnd) selStart = fClickOffset; @@ -3019,8 +3027,9 @@ BTextView::HandleArrowKey(uint32 inArrowKey) // invalidate the null style fStyles->InvalidateNullStyle(); - Select(selStart, selEnd); - + if (selEnd != fSelEnd || selStart != fSelStart) + Select(selStart, selEnd); + // scroll if needed ScrollToOffset(scrollToOffset); } @@ -3217,7 +3226,8 @@ BTextView::HandleAlphaKey(const char *bytes, int32 numBytes) fClickOffset = fSelEnd = fSelStart = fSelStart + numBytes; - Refresh(fSelStart, fSelEnd, refresh, true); + if (Window()) + Refresh(fSelStart, fSelEnd, refresh, true); } @@ -3235,6 +3245,11 @@ BTextView::Refresh(int32 fromOffset, int32 toOffset, bool erase, { // TODO: Cleanup CALLED(); + + ASSERT(Window() != NULL); + if (!Window()) + return; + float saveHeight = fTextRect.Height(); int32 fromLine = LineAt(fromOffset); int32 toLine = LineAt(toOffset); @@ -3705,8 +3720,6 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset, // do we have any text to draw? if (length > 0) { - // iterate through each style on this line - //BPoint startPenLoc; bool foundTab = false; long tabChars = 0; long numTabs = 0; @@ -3714,15 +3727,13 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset, const BFont *font = NULL; const rgb_color *color = NULL; int32 numChars; + // iterate through each style on this line while ((numChars = fStyles->Iterate(offset, length, fInline, &font, &color)) != 0) { SetFont(font); SetHighColor(*color); tabChars = numChars; do { - //if (style->underline) - // startPenLoc = PenLocation(); - foundTab = fText->FindChar(B_TAB, offset, &tabChars); if (foundTab) { for (numTabs = 0; (tabChars + numTabs) < numChars; numTabs++) { @@ -3731,26 +3742,37 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset, } } - // TODO: Revisit this as it looks ugly - // and add clauses support (red highlighing) + // TODO: Revisit this as it looks ugly, and it's not even efficient, + // as the red highlight is drawn over the blue one. if (fInline && fInline->IsActive()) { int32 inlineOffset = fInline->Offset(); int32 inlineLength = fInline->Length(); if (inlineOffset >= offset && inlineOffset + inlineLength <= offset + length) { + float height; BPoint rightBottom = PointAt(inlineOffset + inlineLength, &height); rightBottom.y += height; BRect rect(PointAt(inlineOffset), rightBottom); - PushState(); - - rgb_color blue = {152, 203, 255}; - //rgb_color red = {255, 152, 152}; - SetLowColor(blue); + // Highlight in blue the inputted text + PushState(); + SetLowColor(kBlueInputColor); FillRect(rect, B_SOLID_LOW); - PopState(); + + // Highlight in red the selected part + if (fInline->SelectionLength() > 0) { + rightBottom = PointAt(inlineOffset + fInline->SelectionOffset() + + fInline->SelectionLength(), &height); + rightBottom.y += height; + rect.SetLeftTop(PointAt(inlineOffset + fInline->SelectionOffset())); + rect.SetRightBottom(rightBottom); + PushState(); + SetLowColor(kRedInputColor); + FillRect(rect, B_SOLID_LOW); + PopState(); + } } } @@ -3767,17 +3789,6 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset, tabChars += numTabs; } - /*if (style->underline) { - BPoint savePenLoc = PenLocation(); - BPoint curPenLoc = savePenLoc; - startPenLoc.y += 1.0; - curPenLoc.y += 1.0; - - StrokeLine(startPenLoc, curPenLoc); - - MovePenTo(savePenLoc); - }*/ - offset += tabChars; length -= tabChars; numChars -= tabChars; @@ -4374,6 +4385,9 @@ BTextView::HandleInputMethodChanged(BMessage *message) fInline->ResetClauses(); // Get the clauses, and pass them to the _BInlineInput_ object + // TODO: Find out if what we did it's ok, currently we don't consider clauses + // at all, while the bebook says we should; though the visual effect we obtained + // seems correct. Weird. int32 clauseCount = 0; int32 clauseStart; int32 clauseEnd; @@ -4383,12 +4397,13 @@ BTextView::HandleInputMethodChanged(BMessage *message) clauseCount++; } - int32 selCount = 0; - int32 selection; - while (message->FindInt32("be:selection", selCount, &selection) == B_OK) { - // TODO: Do something with the selection - selCount++; - } + int32 selectionStart = 0; + int32 selectionEnd = 0; + message->FindInt32("be:selection", 0, &selectionStart); + message->FindInt32("be:selection", 1, &selectionEnd); + + fInline->SetSelectionOffset(selectionStart); + fInline->SetSelectionLength(selectionEnd - selectionStart); if (clauseCount > 0) { // Insert the new text @@ -4458,7 +4473,8 @@ BTextView::CancelInputMethod() delete fInline; fInline = NULL; - Refresh(0, fText->Length(), true, false); + if (Window()) + Refresh(0, fText->Length(), true, false); }