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