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
+43 -1
View File
@@ -23,6 +23,11 @@
// Author: Stefano Ceccherini ([email protected]) // Author: Stefano Ceccherini ([email protected])
// Description: Helper class to handle input method requests // 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 "InlineInput.h"
#include <cstdlib> #include <cstdlib>
@@ -43,6 +48,8 @@ _BInlineInput_::_BInlineInput_(BMessenger messenger)
fActive(false), fActive(false),
fOffset(0), fOffset(0),
fLength(0), fLength(0),
fSelectionOffset(0),
fSelectionLength(0),
fNumClauses(0), fNumClauses(0),
fClauses(NULL) 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). /*! \brief Adds a clause (see "The Input Server" sez. for details).
\param start The offset into the string where the clause starts. \param start The offset into the string where the clause starts.
\param end The offset into the string where the clause finishes. \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; return result;
} }
int32
_BInlineInput_::CountClauses() const
{
return fNumClauses;
}
/*! \brief Deletes any added clause. /*! \brief Deletes any added clause.
*/ */
void void
@@ -44,9 +44,16 @@ public:
int32 Offset() const; int32 Offset() const;
void SetOffset(int32 offset); void SetOffset(int32 offset);
int32 SelectionLength() const;
void SetSelectionLength(int32);
int32 SelectionOffset() const;
void SetSelectionOffset(int32 offset);
void AddClause(int32, int32); void AddClause(int32, int32);
bool GetClause(int32 index, int32 *start, int32 *end) const; bool GetClause(int32 index, int32 *start, int32 *end) const;
int32 CountClauses() const;
void ResetClauses(); void ResetClauses();
@@ -58,6 +65,9 @@ private:
int32 fOffset; int32 fOffset;
int32 fLength; int32 fLength;
int32 fSelectionOffset;
int32 fSelectionLength;
int32 fNumClauses; int32 fNumClauses;
clause *fClauses; clause *fClauses;
}; };
+67 -51
View File
@@ -127,7 +127,9 @@ sem_id BTextView::sWidthSem = B_BAD_SEM_ID;
int32 BTextView::sWidthAtom = 0; int32 BTextView::sWidthAtom = 0;
#endif #endif
const static rgb_color kBlueInputColor = { 152, 203, 255 };
const static rgb_color kRedInputColor = { 255, 152, 152 };
static property_info static property_info
sPropertyList[] = { sPropertyList[] = {
{ {
@@ -457,7 +459,8 @@ BTextView::MouseDown(BPoint where)
if (fCaretVisible) if (fCaretVisible)
InvertCaret(); InvertCaret();
int32 mouseOffset = OffsetAt(where); int32 oldOffset = fClickOffset;
fClickOffset = OffsetAt(where);
bool shiftDown = modifiers() & B_SHIFT_KEY; bool shiftDown = modifiers() & B_SHIFT_KEY;
// TODO: Asynchronous mouse tracking // TODO: Asynchronous mouse tracking
@@ -471,7 +474,7 @@ BTextView::MouseDown(BPoint where)
// since dragging works also with the primary button. // since dragging works also with the primary button.
if (buttons == B_SECONDARY_MOUSE_BUTTON) { if (buttons == B_SECONDARY_MOUSE_BUTTON) {
// was the click within the selection range? // was the click within the selection range?
if (mouseOffset >= fSelStart && mouseOffset <= fSelEnd) { if (fClickOffset >= fSelStart && fClickOffset <= fSelEnd) {
InitiateDrag(); InitiateDrag();
return; return;
} }
@@ -492,7 +495,7 @@ BTextView::MouseDown(BPoint where)
// is this a double/triple click, or is it a new click? // is this a double/triple click, or is it a new click?
if (clickSpeed > (system_time() - fClickTime) && if (clickSpeed > (system_time() - fClickTime) &&
mouseOffset == fClickOffset ) { oldOffset == fClickOffset ) {
if (fClickCount > 1) { if (fClickCount > 1) {
// triple click // triple click
fClickCount = 0; fClickCount = 0;
@@ -504,12 +507,11 @@ BTextView::MouseDown(BPoint where)
} }
} else { } else {
// new click // new click
fClickOffset = mouseOffset;
fClickCount = 1; fClickCount = 1;
fClickTime = system_time(); fClickTime = system_time();
if (!shiftDown) { if (!shiftDown) {
Select(mouseOffset, mouseOffset); Select(fClickOffset, fClickOffset);
if (fEditable) if (fEditable)
InvertCaret(); InvertCaret();
} }
@@ -522,15 +524,15 @@ BTextView::MouseDown(BPoint where)
// track the mouse while it's down // track the mouse while it's down
long start = 0; long start = 0;
long end = 0; long end = 0;
long anchor = (mouseOffset > fSelStart) ? fSelStart : fSelEnd; long anchor = (fClickOffset > fSelStart) ? fSelStart : fSelEnd;
BPoint curMouse = where; BPoint curMouse = where;
ulong buttons = 0; ulong buttons = 0;
do { do {
if (mouseOffset > anchor) { if (fClickOffset > anchor) {
start = anchor; start = anchor;
end = mouseOffset; end = fClickOffset;
} else { } else {
start = mouseOffset; start = fClickOffset;
end = anchor; end = anchor;
} }
@@ -543,7 +545,7 @@ BTextView::MouseDown(BPoint where)
case 2: case 2:
// double click, select word by word // double click, select word by word
FindWord(mouseOffset, &start, &end); FindWord(fClickOffset, &start, &end);
break; break;
default: default:
@@ -552,7 +554,7 @@ BTextView::MouseDown(BPoint where)
} }
if (shiftDown) { if (shiftDown) {
if (mouseOffset > anchor) if (fClickOffset > anchor)
start = anchor; start = anchor;
else else
end = anchor; end = anchor;
@@ -590,7 +592,7 @@ BTextView::MouseDown(BPoint where)
snooze(30000); snooze(30000);
GetMouse(&curMouse, &buttons); GetMouse(&curMouse, &buttons);
mouseOffset = OffsetAt(curMouse); fClickOffset = OffsetAt(curMouse);
} while (buttons != 0); } while (buttons != 0);
} }
@@ -2099,7 +2101,8 @@ BTextView::TextHeight(int32 startLine, int32 endLine) const
if (endLine == numLines - 1 && (*fText)[fText->Length() - 1] == '\n') if (endLine == numLines - 1 && (*fText)[fText->Length() - 1] == '\n')
height += (*fLines)[endLine + 1]->origin - (*fLines)[endLine]->origin; height += (*fLines)[endLine + 1]->origin - (*fLines)[endLine]->origin;
height = ceil(height);
return height; return height;
} }
@@ -2952,12 +2955,15 @@ BTextView::HandleArrowKey(uint32 inArrowKey)
case B_LEFT_ARROW: case B_LEFT_ARROW:
if (fClickOffset > 0) if (fClickOffset > 0)
fClickOffset = PreviousInitialByte(fClickOffset); fClickOffset = PreviousInitialByte(fClickOffset);
else if (shiftDown)
return;
if (shiftDown) { if (shiftDown) {
if (fClickOffset >= fSelStart) if (fClickOffset >= fSelStart)
selEnd = fClickOffset; selEnd = fClickOffset;
else else
selStart = fClickOffset; selStart = fClickOffset;
} else } else
selStart = selEnd = fClickOffset; selStart = selEnd = fClickOffset;
@@ -2967,7 +2973,9 @@ BTextView::HandleArrowKey(uint32 inArrowKey)
case B_RIGHT_ARROW: case B_RIGHT_ARROW:
if (fClickOffset < fText->Length()) if (fClickOffset < fText->Length())
fClickOffset = NextInitialByte(fClickOffset); fClickOffset = NextInitialByte(fClickOffset);
else if (shiftDown)
return;
if (shiftDown) { if (shiftDown) {
if (fClickOffset <= fSelEnd) if (fClickOffset <= fSelEnd)
selStart = fClickOffset; selStart = fClickOffset;
@@ -3019,8 +3027,9 @@ BTextView::HandleArrowKey(uint32 inArrowKey)
// invalidate the null style // invalidate the null style
fStyles->InvalidateNullStyle(); fStyles->InvalidateNullStyle();
Select(selStart, selEnd); if (selEnd != fSelEnd || selStart != fSelStart)
Select(selStart, selEnd);
// scroll if needed // scroll if needed
ScrollToOffset(scrollToOffset); ScrollToOffset(scrollToOffset);
} }
@@ -3217,7 +3226,8 @@ BTextView::HandleAlphaKey(const char *bytes, int32 numBytes)
fClickOffset = fSelEnd = fSelStart = fSelStart + 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 // TODO: Cleanup
CALLED(); CALLED();
ASSERT(Window() != NULL);
if (!Window())
return;
float saveHeight = fTextRect.Height(); float saveHeight = fTextRect.Height();
int32 fromLine = LineAt(fromOffset); int32 fromLine = LineAt(fromOffset);
int32 toLine = LineAt(toOffset); int32 toLine = LineAt(toOffset);
@@ -3705,8 +3720,6 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
// do we have any text to draw? // do we have any text to draw?
if (length > 0) { if (length > 0) {
// iterate through each style on this line
//BPoint startPenLoc;
bool foundTab = false; bool foundTab = false;
long tabChars = 0; long tabChars = 0;
long numTabs = 0; long numTabs = 0;
@@ -3714,15 +3727,13 @@ BTextView::DrawLines(int32 startLine, int32 endLine, int32 startOffset,
const BFont *font = NULL; const BFont *font = NULL;
const rgb_color *color = NULL; const rgb_color *color = NULL;
int32 numChars; int32 numChars;
// iterate through each style on this line
while ((numChars = fStyles->Iterate(offset, length, fInline, &font, &color)) != 0) { while ((numChars = fStyles->Iterate(offset, length, fInline, &font, &color)) != 0) {
SetFont(font); SetFont(font);
SetHighColor(*color); SetHighColor(*color);
tabChars = numChars; tabChars = numChars;
do { do {
//if (style->underline)
// startPenLoc = PenLocation();
foundTab = fText->FindChar(B_TAB, offset, &tabChars); foundTab = fText->FindChar(B_TAB, offset, &tabChars);
if (foundTab) { if (foundTab) {
for (numTabs = 0; (tabChars + numTabs) < numChars; numTabs++) { 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 // TODO: Revisit this as it looks ugly, and it's not even efficient,
// and add clauses support (red highlighing) // as the red highlight is drawn over the blue one.
if (fInline && fInline->IsActive()) { if (fInline && fInline->IsActive()) {
int32 inlineOffset = fInline->Offset(); int32 inlineOffset = fInline->Offset();
int32 inlineLength = fInline->Length(); int32 inlineLength = fInline->Length();
if (inlineOffset >= offset && if (inlineOffset >= offset &&
inlineOffset + inlineLength <= offset + length) { inlineOffset + inlineLength <= offset + length) {
float height; float height;
BPoint rightBottom = PointAt(inlineOffset + inlineLength, &height); BPoint rightBottom = PointAt(inlineOffset + inlineLength, &height);
rightBottom.y += height; rightBottom.y += height;
BRect rect(PointAt(inlineOffset), rightBottom); BRect rect(PointAt(inlineOffset), rightBottom);
PushState(); // Highlight in blue the inputted text
PushState();
rgb_color blue = {152, 203, 255}; SetLowColor(kBlueInputColor);
//rgb_color red = {255, 152, 152};
SetLowColor(blue);
FillRect(rect, B_SOLID_LOW); FillRect(rect, B_SOLID_LOW);
PopState(); 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; 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; offset += tabChars;
length -= tabChars; length -= tabChars;
numChars -= tabChars; numChars -= tabChars;
@@ -4374,6 +4385,9 @@ BTextView::HandleInputMethodChanged(BMessage *message)
fInline->ResetClauses(); fInline->ResetClauses();
// Get the clauses, and pass them to the _BInlineInput_ object // 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 clauseCount = 0;
int32 clauseStart; int32 clauseStart;
int32 clauseEnd; int32 clauseEnd;
@@ -4383,12 +4397,13 @@ BTextView::HandleInputMethodChanged(BMessage *message)
clauseCount++; clauseCount++;
} }
int32 selCount = 0; int32 selectionStart = 0;
int32 selection; int32 selectionEnd = 0;
while (message->FindInt32("be:selection", selCount, &selection) == B_OK) { message->FindInt32("be:selection", 0, &selectionStart);
// TODO: Do something with the selection message->FindInt32("be:selection", 1, &selectionEnd);
selCount++;
} fInline->SetSelectionOffset(selectionStart);
fInline->SetSelectionLength(selectionEnd - selectionStart);
if (clauseCount > 0) { if (clauseCount > 0) {
// Insert the new text // Insert the new text
@@ -4458,7 +4473,8 @@ BTextView::CancelInputMethod()
delete fInline; delete fInline;
fInline = NULL; fInline = NULL;
Refresh(0, fText->Length(), true, false); if (Window())
Refresh(0, fText->Length(), true, false);
} }