Finished input method stuff: now we do also the red highlighting.

InlineInput.cpp will probably be simplified in the future.
Some subtle fixes to the keyboard/mouse selection code,
 which wasn't yet behaving as the real BTextView.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9494 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stefano Ceccherini 2004-10-25 06:34:51 +00:00
parent 5a23ac2600
commit a13f233057
3 changed files with 120 additions and 52 deletions

View File

@ -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 <cstdlib>
@ -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

View File

@ -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;
};

View File

@ -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);
}