Terminal: Pull user input handling into state classes
This commit is contained in:
@@ -33,6 +33,7 @@ Application Terminal :
|
|||||||
TermParse.cpp
|
TermParse.cpp
|
||||||
TermScrollView.cpp
|
TermScrollView.cpp
|
||||||
TermView.cpp
|
TermView.cpp
|
||||||
|
TermViewStates.cpp
|
||||||
TermWindow.cpp
|
TermWindow.cpp
|
||||||
TitlePlaceholderMapper.cpp
|
TitlePlaceholderMapper.cpp
|
||||||
VTKeyTbl.c
|
VTKeyTbl.c
|
||||||
|
|||||||
+35
-378
@@ -62,22 +62,13 @@
|
|||||||
#include "TermConst.h"
|
#include "TermConst.h"
|
||||||
#include "TerminalBuffer.h"
|
#include "TerminalBuffer.h"
|
||||||
#include "TerminalCharClassifier.h"
|
#include "TerminalCharClassifier.h"
|
||||||
|
#include "TermViewStates.h"
|
||||||
#include "VTkeymap.h"
|
#include "VTkeymap.h"
|
||||||
|
|
||||||
|
|
||||||
// defined in VTKeyTbl.c
|
|
||||||
extern int function_keycode_table[];
|
|
||||||
extern char *function_key_char_table[];
|
|
||||||
|
|
||||||
#define ROWS_DEFAULT 25
|
#define ROWS_DEFAULT 25
|
||||||
#define COLUMNS_DEFAULT 80
|
#define COLUMNS_DEFAULT 80
|
||||||
|
|
||||||
// selection granularity
|
|
||||||
enum {
|
|
||||||
SELECT_CHARS,
|
|
||||||
SELECT_WORDS,
|
|
||||||
SELECT_LINES
|
|
||||||
};
|
|
||||||
|
|
||||||
#undef B_TRANSLATION_CONTEXT
|
#undef B_TRANSLATION_CONTEXT
|
||||||
#define B_TRANSLATION_CONTEXT "Terminal TermView"
|
#define B_TRANSLATION_CONTEXT "Terminal TermView"
|
||||||
@@ -101,7 +92,6 @@ static property_info sPropList[] = {
|
|||||||
|
|
||||||
static const uint32 kUpdateSigWinch = 'Rwin';
|
static const uint32 kUpdateSigWinch = 'Rwin';
|
||||||
static const uint32 kBlinkCursor = 'BlCr';
|
static const uint32 kBlinkCursor = 'BlCr';
|
||||||
static const uint32 kAutoScroll = 'AScr';
|
|
||||||
|
|
||||||
static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s
|
static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s
|
||||||
|
|
||||||
@@ -320,14 +310,15 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
fConsiderClockedSync = false;
|
fConsiderClockedSync = false;
|
||||||
fSelStart = TermPos(-1, -1);
|
fSelStart = TermPos(-1, -1);
|
||||||
fSelEnd = TermPos(-1, -1);
|
fSelEnd = TermPos(-1, -1);
|
||||||
fMouseTracking = false;
|
|
||||||
fCheckMouseTracking = false;
|
|
||||||
fPrevPos = TermPos(-1, - 1);
|
fPrevPos = TermPos(-1, - 1);
|
||||||
fReportX10MouseEvent = false;
|
fReportX10MouseEvent = false;
|
||||||
fReportNormalMouseEvent = false;
|
fReportNormalMouseEvent = false;
|
||||||
fReportButtonMouseEvent = false;
|
fReportButtonMouseEvent = false;
|
||||||
fReportAnyMouseEvent = false;
|
fReportAnyMouseEvent = false;
|
||||||
fMouseClipboard = be_clipboard;
|
fMouseClipboard = be_clipboard;
|
||||||
|
fDefaultState = new(std::nothrow) DefaultState(this);
|
||||||
|
fSelectState = new(std::nothrow) SelectState(this);
|
||||||
|
fActiveState = NULL;
|
||||||
|
|
||||||
fTextBuffer = new(std::nothrow) TerminalBuffer;
|
fTextBuffer = new(std::nothrow) TerminalBuffer;
|
||||||
if (fTextBuffer == NULL)
|
if (fTextBuffer == NULL)
|
||||||
@@ -371,9 +362,14 @@ TermView::_InitObject(const ShellParameters& shellParameters)
|
|||||||
if (error < B_OK)
|
if (error < B_OK)
|
||||||
return error;
|
return error;
|
||||||
|
|
||||||
|
if (fDefaultState == NULL || fSelectState == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
SetLowColor(fTextBackColor);
|
SetLowColor(fTextBackColor);
|
||||||
SetViewColor(B_TRANSPARENT_32_BIT);
|
SetViewColor(B_TRANSPARENT_32_BIT);
|
||||||
|
|
||||||
|
_NextState(fDefaultState);
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,6 +381,8 @@ TermView::~TermView()
|
|||||||
|
|
||||||
_DetachShell();
|
_DetachShell();
|
||||||
|
|
||||||
|
delete fDefaultState;
|
||||||
|
delete fSelectState;
|
||||||
delete fSyncRunner;
|
delete fSyncRunner;
|
||||||
delete fAutoScrollRunner;
|
delete fAutoScrollRunner;
|
||||||
delete fCharClassifier;
|
delete fCharClassifier;
|
||||||
@@ -1388,165 +1386,7 @@ TermView::MakeFocus(bool focusState)
|
|||||||
void
|
void
|
||||||
TermView::KeyDown(const char *bytes, int32 numBytes)
|
TermView::KeyDown(const char *bytes, int32 numBytes)
|
||||||
{
|
{
|
||||||
int32 key, mod, rawChar;
|
fActiveState->KeyDown(bytes, numBytes);
|
||||||
BMessage *currentMessage = Looper()->CurrentMessage();
|
|
||||||
if (currentMessage == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
currentMessage->FindInt32("modifiers", &mod);
|
|
||||||
currentMessage->FindInt32("key", &key);
|
|
||||||
currentMessage->FindInt32("raw_char", &rawChar);
|
|
||||||
|
|
||||||
_ActivateCursor(true);
|
|
||||||
|
|
||||||
// handle multi-byte chars
|
|
||||||
if (numBytes > 1) {
|
|
||||||
if (fEncoding != M_UTF8) {
|
|
||||||
char destBuffer[16];
|
|
||||||
int32 destLen = sizeof(destBuffer);
|
|
||||||
int32 state = 0;
|
|
||||||
convert_from_utf8(fEncoding, bytes, &numBytes, destBuffer,
|
|
||||||
&destLen, &state, '?');
|
|
||||||
_ScrollTo(0, true);
|
|
||||||
fShell->Write(destBuffer, destLen);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ScrollTo(0, true);
|
|
||||||
fShell->Write(bytes, numBytes);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Terminal filters RET, ENTER, F1...F12, and ARROW key code.
|
|
||||||
const char *toWrite = NULL;
|
|
||||||
|
|
||||||
switch (*bytes) {
|
|
||||||
case B_RETURN:
|
|
||||||
if (rawChar == B_RETURN)
|
|
||||||
toWrite = "\r";
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_DELETE:
|
|
||||||
toWrite = DELETE_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_BACKSPACE:
|
|
||||||
// Translate only the actual backspace key to the backspace
|
|
||||||
// code. CTRL-H shall just be echoed.
|
|
||||||
if (!((mod & B_CONTROL_KEY) && rawChar == 'h'))
|
|
||||||
toWrite = BACKSPACE_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_LEFT_ARROW:
|
|
||||||
if (rawChar == B_LEFT_ARROW) {
|
|
||||||
if ((mod & B_SHIFT_KEY) != 0) {
|
|
||||||
if (fListener != NULL)
|
|
||||||
fListener->PreviousTermView(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY))
|
|
||||||
toWrite = CTRL_LEFT_ARROW_KEY_CODE;
|
|
||||||
else
|
|
||||||
toWrite = LEFT_ARROW_KEY_CODE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_RIGHT_ARROW:
|
|
||||||
if (rawChar == B_RIGHT_ARROW) {
|
|
||||||
if ((mod & B_SHIFT_KEY) != 0) {
|
|
||||||
if (fListener != NULL)
|
|
||||||
fListener->NextTermView(this);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY))
|
|
||||||
toWrite = CTRL_RIGHT_ARROW_KEY_CODE;
|
|
||||||
else
|
|
||||||
toWrite = RIGHT_ARROW_KEY_CODE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_UP_ARROW:
|
|
||||||
if (mod & B_SHIFT_KEY) {
|
|
||||||
_ScrollTo(fScrollOffset - fFontHeight, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rawChar == B_UP_ARROW) {
|
|
||||||
if (mod & B_CONTROL_KEY)
|
|
||||||
toWrite = CTRL_UP_ARROW_KEY_CODE;
|
|
||||||
else
|
|
||||||
toWrite = UP_ARROW_KEY_CODE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_DOWN_ARROW:
|
|
||||||
if (mod & B_SHIFT_KEY) {
|
|
||||||
_ScrollTo(fScrollOffset + fFontHeight, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rawChar == B_DOWN_ARROW) {
|
|
||||||
if (mod & B_CONTROL_KEY)
|
|
||||||
toWrite = CTRL_DOWN_ARROW_KEY_CODE;
|
|
||||||
else
|
|
||||||
toWrite = DOWN_ARROW_KEY_CODE;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_INSERT:
|
|
||||||
if (rawChar == B_INSERT)
|
|
||||||
toWrite = INSERT_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_HOME:
|
|
||||||
if (rawChar == B_HOME)
|
|
||||||
toWrite = HOME_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_END:
|
|
||||||
if (rawChar == B_END)
|
|
||||||
toWrite = END_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_PAGE_UP:
|
|
||||||
if (mod & B_SHIFT_KEY) {
|
|
||||||
_ScrollTo(fScrollOffset - fFontHeight * fRows, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rawChar == B_PAGE_UP)
|
|
||||||
toWrite = PAGE_UP_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_PAGE_DOWN:
|
|
||||||
if (mod & B_SHIFT_KEY) {
|
|
||||||
_ScrollTo(fScrollOffset + fFontHeight * fRows, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (rawChar == B_PAGE_DOWN)
|
|
||||||
toWrite = PAGE_DOWN_KEY_CODE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case B_FUNCTION_KEY:
|
|
||||||
for (int32 i = 0; i < 12; i++) {
|
|
||||||
if (key == function_keycode_table[i]) {
|
|
||||||
toWrite = function_key_char_table[i];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the above code proposed an alternative string to write, we get it's
|
|
||||||
// length. Otherwise we write exactly the bytes passed to this method.
|
|
||||||
size_t toWriteLen;
|
|
||||||
if (toWrite != NULL) {
|
|
||||||
toWriteLen = strlen(toWrite);
|
|
||||||
} else {
|
|
||||||
toWrite = bytes;
|
|
||||||
toWriteLen = numBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
_ScrollTo(0, true);
|
|
||||||
fShell->Write(toWrite, toWriteLen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1593,6 +1433,9 @@ TermView::FrameResized(float width, float height)
|
|||||||
void
|
void
|
||||||
TermView::MessageReceived(BMessage *msg)
|
TermView::MessageReceived(BMessage *msg)
|
||||||
{
|
{
|
||||||
|
if (fActiveState->MessageReceived(msg))
|
||||||
|
return;
|
||||||
|
|
||||||
entry_ref ref;
|
entry_ref ref;
|
||||||
const char *ctrl_l = "\x0c";
|
const char *ctrl_l = "\x0c";
|
||||||
|
|
||||||
@@ -1829,9 +1672,6 @@ TermView::MessageReceived(BMessage *msg)
|
|||||||
case kUpdateSigWinch:
|
case kUpdateSigWinch:
|
||||||
_UpdateSIGWINCH();
|
_UpdateSIGWINCH();
|
||||||
break;
|
break;
|
||||||
case kAutoScroll:
|
|
||||||
_AutoScrollUpdate();
|
|
||||||
break;
|
|
||||||
case kSecondaryMouseDropAction:
|
case kSecondaryMouseDropAction:
|
||||||
_DoSecondaryMouseDropAction(msg);
|
_DoSecondaryMouseDropAction(msg);
|
||||||
break;
|
break;
|
||||||
@@ -2480,98 +2320,13 @@ TermView::MouseDown(BPoint where)
|
|||||||
if (!IsFocus())
|
if (!IsFocus())
|
||||||
MakeFocus();
|
MakeFocus();
|
||||||
|
|
||||||
int32 buttons;
|
BMessage* currentMessage = Window()->CurrentMessage();
|
||||||
int32 modifier;
|
int32 buttons = currentMessage->GetInt32("buttons", 0);
|
||||||
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
|
int32 modifiers = currentMessage->GetInt32("modifiers", 0);
|
||||||
Window()->CurrentMessage()->FindInt32("modifiers", &modifier);
|
|
||||||
|
fActiveState->MouseDown(where, buttons, modifiers);
|
||||||
|
|
||||||
fMouseButtons = buttons;
|
fMouseButtons = buttons;
|
||||||
|
|
||||||
if (fReportAnyMouseEvent || fReportButtonMouseEvent
|
|
||||||
|| fReportNormalMouseEvent || fReportX10MouseEvent) {
|
|
||||||
TermPos clickPos = _ConvertToTerminal(where);
|
|
||||||
_SendMouseEvent(buttons, modifier, clickPos.x, clickPos.y, false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// paste button
|
|
||||||
if ((buttons & (B_SECONDARY_MOUSE_BUTTON | B_TERTIARY_MOUSE_BUTTON)) != 0) {
|
|
||||||
Paste(fMouseClipboard);
|
|
||||||
fLastClickPoint = where;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Select Region
|
|
||||||
if (buttons == B_PRIMARY_MOUSE_BUTTON) {
|
|
||||||
int32 clicks;
|
|
||||||
Window()->CurrentMessage()->FindInt32("clicks", &clicks);
|
|
||||||
|
|
||||||
if (_HasSelection()) {
|
|
||||||
TermPos inPos = _ConvertToTerminal(where);
|
|
||||||
if (_CheckSelectedRegion(inPos)) {
|
|
||||||
if (modifier & B_CONTROL_KEY) {
|
|
||||||
BPoint p;
|
|
||||||
uint32 bt;
|
|
||||||
do {
|
|
||||||
GetMouse(&p, &bt);
|
|
||||||
|
|
||||||
if (bt == 0) {
|
|
||||||
_Deselect();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
snooze(40000);
|
|
||||||
|
|
||||||
} while (abs((int)(where.x - p.x)) < 4
|
|
||||||
&& abs((int)(where.y - p.y)) < 4);
|
|
||||||
|
|
||||||
InitiateDrag();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If mouse has moved too much, disable double/triple click.
|
|
||||||
if (_MouseDistanceSinceLastClick(where) > 8)
|
|
||||||
clicks = 1;
|
|
||||||
|
|
||||||
SetMouseEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS,
|
|
||||||
B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);
|
|
||||||
|
|
||||||
TermPos clickPos = _ConvertToTerminal(where);
|
|
||||||
|
|
||||||
if (modifier & B_SHIFT_KEY) {
|
|
||||||
fInitialSelectionStart = clickPos;
|
|
||||||
fInitialSelectionEnd = clickPos;
|
|
||||||
_ExtendSelection(fInitialSelectionStart, true, false);
|
|
||||||
} else {
|
|
||||||
_Deselect();
|
|
||||||
fInitialSelectionStart = clickPos;
|
|
||||||
fInitialSelectionEnd = clickPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If clicks larger than 3, reset mouse click counter.
|
|
||||||
clicks = (clicks - 1) % 3 + 1;
|
|
||||||
|
|
||||||
switch (clicks) {
|
|
||||||
case 1:
|
|
||||||
fCheckMouseTracking = true;
|
|
||||||
fSelectGranularity = SELECT_CHARS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
_SelectWord(where, (modifier & B_SHIFT_KEY) != 0, false);
|
|
||||||
fMouseTracking = true;
|
|
||||||
fSelectGranularity = SELECT_WORDS;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 3:
|
|
||||||
_SelectLine(where, (modifier & B_SHIFT_KEY) != 0, false);
|
|
||||||
fMouseTracking = true;
|
|
||||||
fSelectGranularity = SELECT_LINES;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fLastClickPoint = where;
|
fLastClickPoint = where;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2579,111 +2334,17 @@ TermView::MouseDown(BPoint where)
|
|||||||
void
|
void
|
||||||
TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message)
|
TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message)
|
||||||
{
|
{
|
||||||
if (fReportAnyMouseEvent || fReportButtonMouseEvent) {
|
fActiveState->MouseMoved(where, transit, message);
|
||||||
int32 modifier;
|
|
||||||
Window()->CurrentMessage()->FindInt32("modifiers", &modifier);
|
|
||||||
|
|
||||||
TermPos clickPos = _ConvertToTerminal(where);
|
|
||||||
|
|
||||||
if (fReportButtonMouseEvent) {
|
|
||||||
if (fPrevPos.x != clickPos.x || fPrevPos.y != clickPos.y) {
|
|
||||||
_SendMouseEvent(fMouseButtons, modifier, clickPos.x, clickPos.y,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
fPrevPos = clickPos;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
_SendMouseEvent(fMouseButtons, modifier, clickPos.x, clickPos.y, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fCheckMouseTracking) {
|
|
||||||
if (_MouseDistanceSinceLastClick(where) > 9)
|
|
||||||
fMouseTracking = true;
|
|
||||||
}
|
|
||||||
if (!fMouseTracking)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool doAutoScroll = false;
|
|
||||||
|
|
||||||
if (where.y < 0) {
|
|
||||||
doAutoScroll = true;
|
|
||||||
fAutoScrollSpeed = where.y;
|
|
||||||
where.x = 0;
|
|
||||||
where.y = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
BRect bounds(Bounds());
|
|
||||||
if (where.y > bounds.bottom) {
|
|
||||||
doAutoScroll = true;
|
|
||||||
fAutoScrollSpeed = where.y - bounds.bottom;
|
|
||||||
where.x = bounds.right;
|
|
||||||
where.y = bounds.bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doAutoScroll) {
|
|
||||||
if (fAutoScrollRunner == NULL) {
|
|
||||||
BMessage message(kAutoScroll);
|
|
||||||
fAutoScrollRunner = new (std::nothrow) BMessageRunner(
|
|
||||||
BMessenger(this), &message, 10000);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
delete fAutoScrollRunner;
|
|
||||||
fAutoScrollRunner = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (fSelectGranularity) {
|
|
||||||
case SELECT_CHARS:
|
|
||||||
{
|
|
||||||
// If we just start selecting, we first select the initially
|
|
||||||
// hit char, so that we get a proper initial selection -- the char
|
|
||||||
// in question, which will thus always be selected, regardless of
|
|
||||||
// whether selecting forward or backward.
|
|
||||||
if (fInitialSelectionStart == fInitialSelectionEnd) {
|
|
||||||
_Select(fInitialSelectionStart, fInitialSelectionEnd, true,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
|
|
||||||
_ExtendSelection(_ConvertToTerminal(where), true, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SELECT_WORDS:
|
|
||||||
_SelectWord(where, true, true);
|
|
||||||
break;
|
|
||||||
case SELECT_LINES:
|
|
||||||
_SelectLine(where, true, true);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
TermView::MouseUp(BPoint where)
|
TermView::MouseUp(BPoint where)
|
||||||
{
|
{
|
||||||
fCheckMouseTracking = false;
|
int32 buttons = Window()->CurrentMessage()->GetInt32("buttons", 0);
|
||||||
fMouseTracking = false;
|
|
||||||
|
|
||||||
if (fAutoScrollRunner != NULL) {
|
fActiveState->MouseUp(where, buttons);
|
||||||
delete fAutoScrollRunner;
|
|
||||||
fAutoScrollRunner = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// When releasing the first mouse button, we copy the selected text to the
|
|
||||||
// clipboard.
|
|
||||||
int32 buttons;
|
|
||||||
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
|
|
||||||
|
|
||||||
if (fReportAnyMouseEvent || fReportButtonMouseEvent
|
|
||||||
|| fReportNormalMouseEvent) {
|
|
||||||
TermPos clickPos = _ConvertToTerminal(where);
|
|
||||||
_SendMouseEvent(0, 0, clickPos.x, clickPos.y, false);
|
|
||||||
} else {
|
|
||||||
if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0
|
|
||||||
&& (fMouseButtons & B_PRIMARY_MOUSE_BUTTON) != 0) {
|
|
||||||
Copy(fMouseClipboard);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
fMouseButtons = buttons;
|
fMouseButtons = buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2844,22 +2505,6 @@ TermView::_SelectLine(BPoint where, bool extend, bool useInitialSelection)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
|
||||||
TermView::_AutoScrollUpdate()
|
|
||||||
{
|
|
||||||
if (fMouseTracking && fAutoScrollRunner != NULL && fScrollBar != NULL) {
|
|
||||||
float value = fScrollBar->Value();
|
|
||||||
_ScrollTo(value + fAutoScrollSpeed, true);
|
|
||||||
if (fAutoScrollSpeed < 0) {
|
|
||||||
_ExtendSelection(_ConvertToTerminal(BPoint(0, 0)), true, true);
|
|
||||||
} else {
|
|
||||||
_ExtendSelection(_ConvertToTerminal(Bounds().RightBottom()), true,
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool
|
bool
|
||||||
TermView::_CheckSelectedRegion(const TermPos &pos) const
|
TermView::_CheckSelectedRegion(const TermPos &pos) const
|
||||||
{
|
{
|
||||||
@@ -3222,6 +2867,18 @@ TermView::_CancelInputMethod()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::_NextState(State* state)
|
||||||
|
{
|
||||||
|
if (state != fActiveState) {
|
||||||
|
if (fActiveState != NULL)
|
||||||
|
fActiveState->Exited();
|
||||||
|
fActiveState = state;
|
||||||
|
fActiveState->Entered();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// #pragma mark - Listener
|
// #pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -143,6 +143,16 @@ protected:
|
|||||||
private:
|
private:
|
||||||
class CharClassifier;
|
class CharClassifier;
|
||||||
|
|
||||||
|
class State;
|
||||||
|
class StandardBaseState;
|
||||||
|
class DefaultState;
|
||||||
|
class SelectState;
|
||||||
|
|
||||||
|
friend class State;
|
||||||
|
friend class StandardBaseState;
|
||||||
|
friend class DefaultState;
|
||||||
|
friend class SelectState;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// point and text offset conversion
|
// point and text offset conversion
|
||||||
inline int32 _LineAt(float y);
|
inline int32 _LineAt(float y);
|
||||||
@@ -199,8 +209,6 @@ private:
|
|||||||
void _SelectLine(BPoint where, bool extend,
|
void _SelectLine(BPoint where, bool extend,
|
||||||
bool useInitialSelection);
|
bool useInitialSelection);
|
||||||
|
|
||||||
void _AutoScrollUpdate();
|
|
||||||
|
|
||||||
bool _CheckSelectedRegion(const TermPos& pos) const;
|
bool _CheckSelectedRegion(const TermPos& pos) const;
|
||||||
bool _CheckSelectedRegion(int32 row,
|
bool _CheckSelectedRegion(int32 row,
|
||||||
int32 firstColumn, int32& lastColumn) const;
|
int32 firstColumn, int32& lastColumn) const;
|
||||||
@@ -218,6 +226,8 @@ private:
|
|||||||
void _HandleInputMethodLocationRequest();
|
void _HandleInputMethodLocationRequest();
|
||||||
void _CancelInputMethod();
|
void _CancelInputMethod();
|
||||||
|
|
||||||
|
void _NextState(State* state);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Listener* fListener;
|
Listener* fListener;
|
||||||
Shell* fShell;
|
Shell* fShell;
|
||||||
@@ -252,8 +262,6 @@ private:
|
|||||||
// Cursor position.
|
// Cursor position.
|
||||||
TermPos fCursor;
|
TermPos fCursor;
|
||||||
|
|
||||||
int32 fMouseButtons;
|
|
||||||
|
|
||||||
// Terminal rows and columns.
|
// Terminal rows and columns.
|
||||||
int fColumns;
|
int fColumns;
|
||||||
int fRows;
|
int fRows;
|
||||||
@@ -293,18 +301,21 @@ private:
|
|||||||
TermPos fSelEnd;
|
TermPos fSelEnd;
|
||||||
TermPos fInitialSelectionStart;
|
TermPos fInitialSelectionStart;
|
||||||
TermPos fInitialSelectionEnd;
|
TermPos fInitialSelectionEnd;
|
||||||
bool fMouseTracking;
|
|
||||||
bool fCheckMouseTracking;
|
|
||||||
int fSelectGranularity;
|
|
||||||
BPoint fLastClickPoint;
|
BPoint fLastClickPoint;
|
||||||
|
|
||||||
// mouse
|
// mouse
|
||||||
|
int32 fMouseButtons;
|
||||||
TermPos fPrevPos;
|
TermPos fPrevPos;
|
||||||
bool fReportX10MouseEvent;
|
bool fReportX10MouseEvent;
|
||||||
bool fReportNormalMouseEvent;
|
bool fReportNormalMouseEvent;
|
||||||
bool fReportButtonMouseEvent;
|
bool fReportButtonMouseEvent;
|
||||||
bool fReportAnyMouseEvent;
|
bool fReportAnyMouseEvent;
|
||||||
BClipboard* fMouseClipboard;
|
BClipboard* fMouseClipboard;
|
||||||
|
|
||||||
|
// states
|
||||||
|
DefaultState* fDefaultState;
|
||||||
|
SelectState* fSelectState;
|
||||||
|
State* fActiveState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,563 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2001-2013, Haiku, Inc.
|
||||||
|
* Copyright 2003-2004 Kian Duffy, myob@users.sourceforge.net
|
||||||
|
* Parts Copyright 1998-1999 Kazuho Okui and Takashi Murai.
|
||||||
|
* All rights reserved. Distributed under the terms of the MIT license.
|
||||||
|
*
|
||||||
|
* Authors:
|
||||||
|
* Stefano Ceccherini, stefano.ceccherini@gmail.com
|
||||||
|
* Kian Duffy, myob@users.sourceforge.net
|
||||||
|
* Y.Hayakawa, hida@sawada.riec.tohoku.ac.jp
|
||||||
|
* Ingo Weinhold, ingo_weinhold@gmx.de
|
||||||
|
* Clemens Zeidler, haiku@Clemens-Zeidler.de
|
||||||
|
* Siarzhuk Zharski, zharik@gmx.li
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "TermViewStates.h"
|
||||||
|
|
||||||
|
#include <MessageRunner.h>
|
||||||
|
#include <ScrollBar.h>
|
||||||
|
#include <UTF8.h>
|
||||||
|
#include <Window.h>
|
||||||
|
|
||||||
|
#include "Shell.h"
|
||||||
|
#include "TermConst.h"
|
||||||
|
#include "VTkeymap.h"
|
||||||
|
#include "VTKeyTbl.h"
|
||||||
|
|
||||||
|
|
||||||
|
// selection granularity
|
||||||
|
enum {
|
||||||
|
SELECT_CHARS,
|
||||||
|
SELECT_WORDS,
|
||||||
|
SELECT_LINES
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint32 kAutoScroll = 'AScr';
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - State
|
||||||
|
|
||||||
|
|
||||||
|
TermView::State::State(TermView* view)
|
||||||
|
:
|
||||||
|
fView(view)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TermView::State::~State()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::Entered()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::Exited()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::State::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::KeyDown(const char* bytes, int32 numBytes)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::MouseDown(BPoint where, int32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::State::MouseUp(BPoint where, int32 buttons)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - StandardBaseState
|
||||||
|
|
||||||
|
|
||||||
|
TermView::StandardBaseState::StandardBaseState(TermView* view)
|
||||||
|
:
|
||||||
|
State(view)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::StandardBaseState::_StandardMouseMoved(BPoint where)
|
||||||
|
{
|
||||||
|
if (!fView->fReportAnyMouseEvent && !fView->fReportButtonMouseEvent)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
int32 modifier;
|
||||||
|
fView->Window()->CurrentMessage()->FindInt32("modifiers", &modifier);
|
||||||
|
|
||||||
|
TermPos clickPos = fView->_ConvertToTerminal(where);
|
||||||
|
|
||||||
|
if (fView->fReportButtonMouseEvent) {
|
||||||
|
if (fView->fPrevPos.x != clickPos.x
|
||||||
|
|| fView->fPrevPos.y != clickPos.y) {
|
||||||
|
fView->_SendMouseEvent(fView->fMouseButtons, modifier,
|
||||||
|
clickPos.x, clickPos.y, true);
|
||||||
|
}
|
||||||
|
fView->fPrevPos = clickPos;
|
||||||
|
} else {
|
||||||
|
fView->_SendMouseEvent(fView->fMouseButtons, modifier, clickPos.x,
|
||||||
|
clickPos.y, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - DefaultState
|
||||||
|
|
||||||
|
|
||||||
|
TermView::DefaultState::DefaultState(TermView* view)
|
||||||
|
:
|
||||||
|
StandardBaseState(view)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::DefaultState::KeyDown(const char* bytes, int32 numBytes)
|
||||||
|
{
|
||||||
|
int32 key, mod, rawChar;
|
||||||
|
BMessage *currentMessage = fView->Looper()->CurrentMessage();
|
||||||
|
if (currentMessage == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
currentMessage->FindInt32("modifiers", &mod);
|
||||||
|
currentMessage->FindInt32("key", &key);
|
||||||
|
currentMessage->FindInt32("raw_char", &rawChar);
|
||||||
|
|
||||||
|
fView->_ActivateCursor(true);
|
||||||
|
|
||||||
|
// handle multi-byte chars
|
||||||
|
if (numBytes > 1) {
|
||||||
|
if (fView->fEncoding != M_UTF8) {
|
||||||
|
char destBuffer[16];
|
||||||
|
int32 destLen = sizeof(destBuffer);
|
||||||
|
int32 state = 0;
|
||||||
|
convert_from_utf8(fView->fEncoding, bytes, &numBytes, destBuffer,
|
||||||
|
&destLen, &state, '?');
|
||||||
|
fView->_ScrollTo(0, true);
|
||||||
|
fView->fShell->Write(destBuffer, destLen);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fView->_ScrollTo(0, true);
|
||||||
|
fView->fShell->Write(bytes, numBytes);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminal filters RET, ENTER, F1...F12, and ARROW key code.
|
||||||
|
const char *toWrite = NULL;
|
||||||
|
|
||||||
|
switch (*bytes) {
|
||||||
|
case B_RETURN:
|
||||||
|
if (rawChar == B_RETURN)
|
||||||
|
toWrite = "\r";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_DELETE:
|
||||||
|
toWrite = DELETE_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_BACKSPACE:
|
||||||
|
// Translate only the actual backspace key to the backspace
|
||||||
|
// code. CTRL-H shall just be echoed.
|
||||||
|
if (!((mod & B_CONTROL_KEY) && rawChar == 'h'))
|
||||||
|
toWrite = BACKSPACE_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_LEFT_ARROW:
|
||||||
|
if (rawChar == B_LEFT_ARROW) {
|
||||||
|
if ((mod & B_SHIFT_KEY) != 0) {
|
||||||
|
if (fView->fListener != NULL)
|
||||||
|
fView->fListener->PreviousTermView(fView);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY))
|
||||||
|
toWrite = CTRL_LEFT_ARROW_KEY_CODE;
|
||||||
|
else
|
||||||
|
toWrite = LEFT_ARROW_KEY_CODE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_RIGHT_ARROW:
|
||||||
|
if (rawChar == B_RIGHT_ARROW) {
|
||||||
|
if ((mod & B_SHIFT_KEY) != 0) {
|
||||||
|
if (fView->fListener != NULL)
|
||||||
|
fView->fListener->NextTermView(fView);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((mod & B_CONTROL_KEY) || (mod & B_COMMAND_KEY))
|
||||||
|
toWrite = CTRL_RIGHT_ARROW_KEY_CODE;
|
||||||
|
else
|
||||||
|
toWrite = RIGHT_ARROW_KEY_CODE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_UP_ARROW:
|
||||||
|
if (mod & B_SHIFT_KEY) {
|
||||||
|
fView->_ScrollTo(fView->fScrollOffset - fView->fFontHeight,
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rawChar == B_UP_ARROW) {
|
||||||
|
if (mod & B_CONTROL_KEY)
|
||||||
|
toWrite = CTRL_UP_ARROW_KEY_CODE;
|
||||||
|
else
|
||||||
|
toWrite = UP_ARROW_KEY_CODE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_DOWN_ARROW:
|
||||||
|
if (mod & B_SHIFT_KEY) {
|
||||||
|
fView->_ScrollTo(fView->fScrollOffset + fView->fFontHeight,
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rawChar == B_DOWN_ARROW) {
|
||||||
|
if (mod & B_CONTROL_KEY)
|
||||||
|
toWrite = CTRL_DOWN_ARROW_KEY_CODE;
|
||||||
|
else
|
||||||
|
toWrite = DOWN_ARROW_KEY_CODE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_INSERT:
|
||||||
|
if (rawChar == B_INSERT)
|
||||||
|
toWrite = INSERT_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_HOME:
|
||||||
|
if (rawChar == B_HOME)
|
||||||
|
toWrite = HOME_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_END:
|
||||||
|
if (rawChar == B_END)
|
||||||
|
toWrite = END_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_PAGE_UP:
|
||||||
|
if (mod & B_SHIFT_KEY) {
|
||||||
|
fView->_ScrollTo(
|
||||||
|
fView->fScrollOffset - fView->fFontHeight * fView->fRows,
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rawChar == B_PAGE_UP)
|
||||||
|
toWrite = PAGE_UP_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_PAGE_DOWN:
|
||||||
|
if (mod & B_SHIFT_KEY) {
|
||||||
|
fView->_ScrollTo(
|
||||||
|
fView->fScrollOffset + fView->fFontHeight * fView->fRows,
|
||||||
|
true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rawChar == B_PAGE_DOWN)
|
||||||
|
toWrite = PAGE_DOWN_KEY_CODE;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case B_FUNCTION_KEY:
|
||||||
|
for (int32 i = 0; i < 12; i++) {
|
||||||
|
if (key == function_keycode_table[i]) {
|
||||||
|
toWrite = function_key_char_table[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the above code proposed an alternative string to write, we get it's
|
||||||
|
// length. Otherwise we write exactly the bytes passed to this method.
|
||||||
|
size_t toWriteLen;
|
||||||
|
if (toWrite != NULL) {
|
||||||
|
toWriteLen = strlen(toWrite);
|
||||||
|
} else {
|
||||||
|
toWrite = bytes;
|
||||||
|
toWriteLen = numBytes;
|
||||||
|
}
|
||||||
|
|
||||||
|
fView->_ScrollTo(0, true);
|
||||||
|
fView->fShell->Write(toWrite, toWriteLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::DefaultState::MouseDown(BPoint where, int32 buttons, int32 modifiers)
|
||||||
|
{
|
||||||
|
if (fView->fReportAnyMouseEvent || fView->fReportButtonMouseEvent
|
||||||
|
|| fView->fReportNormalMouseEvent || fView->fReportX10MouseEvent) {
|
||||||
|
TermPos clickPos = fView->_ConvertToTerminal(where);
|
||||||
|
fView->_SendMouseEvent(buttons, modifiers, clickPos.x, clickPos.y,
|
||||||
|
false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// paste button
|
||||||
|
if ((buttons & (B_SECONDARY_MOUSE_BUTTON | B_TERTIARY_MOUSE_BUTTON)) != 0) {
|
||||||
|
fView->Paste(fView->fMouseClipboard);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Select Region
|
||||||
|
if (buttons == B_PRIMARY_MOUSE_BUTTON) {
|
||||||
|
fView->fSelectState->Prepare(where, modifiers);
|
||||||
|
fView->_NextState(fView->fSelectState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::DefaultState::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message)
|
||||||
|
{
|
||||||
|
_StandardMouseMoved(where);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #pragma mark - SelectState
|
||||||
|
|
||||||
|
|
||||||
|
TermView::SelectState::SelectState(TermView* view)
|
||||||
|
:
|
||||||
|
StandardBaseState(view),
|
||||||
|
fSelectGranularity(SELECT_CHARS),
|
||||||
|
fCheckMouseTracking(false),
|
||||||
|
fMouseTracking(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::SelectState::Prepare(BPoint where, int32 modifiers)
|
||||||
|
{
|
||||||
|
int32 clicks;
|
||||||
|
fView->Window()->CurrentMessage()->FindInt32("clicks", &clicks);
|
||||||
|
|
||||||
|
if (fView->_HasSelection()) {
|
||||||
|
TermPos inPos = fView->_ConvertToTerminal(where);
|
||||||
|
if (fView->_CheckSelectedRegion(inPos)) {
|
||||||
|
if (modifiers & B_CONTROL_KEY) {
|
||||||
|
BPoint p;
|
||||||
|
uint32 bt;
|
||||||
|
do {
|
||||||
|
fView->GetMouse(&p, &bt);
|
||||||
|
|
||||||
|
if (bt == 0) {
|
||||||
|
fView->_Deselect();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
snooze(40000);
|
||||||
|
|
||||||
|
} while (abs((int)(where.x - p.x)) < 4
|
||||||
|
&& abs((int)(where.y - p.y)) < 4);
|
||||||
|
|
||||||
|
fView->InitiateDrag();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If mouse has moved too much, disable double/triple click.
|
||||||
|
if (fView->_MouseDistanceSinceLastClick(where) > 8)
|
||||||
|
clicks = 1;
|
||||||
|
|
||||||
|
fView->SetMouseEventMask(B_POINTER_EVENTS | B_KEYBOARD_EVENTS,
|
||||||
|
B_NO_POINTER_HISTORY | B_LOCK_WINDOW_FOCUS);
|
||||||
|
|
||||||
|
TermPos clickPos = fView->_ConvertToTerminal(where);
|
||||||
|
|
||||||
|
if (modifiers & B_SHIFT_KEY) {
|
||||||
|
fView->fInitialSelectionStart = clickPos;
|
||||||
|
fView->fInitialSelectionEnd = clickPos;
|
||||||
|
fView->_ExtendSelection(fView->fInitialSelectionStart, true, false);
|
||||||
|
} else {
|
||||||
|
fView->_Deselect();
|
||||||
|
fView->fInitialSelectionStart = clickPos;
|
||||||
|
fView->fInitialSelectionEnd = clickPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If clicks larger than 3, reset mouse click counter.
|
||||||
|
clicks = (clicks - 1) % 3 + 1;
|
||||||
|
|
||||||
|
switch (clicks) {
|
||||||
|
case 1:
|
||||||
|
fCheckMouseTracking = true;
|
||||||
|
fSelectGranularity = SELECT_CHARS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
fView->_SelectWord(where, (modifiers & B_SHIFT_KEY) != 0, false);
|
||||||
|
fMouseTracking = true;
|
||||||
|
fSelectGranularity = SELECT_WORDS;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
fView->_SelectLine(where, (modifiers & B_SHIFT_KEY) != 0, false);
|
||||||
|
fMouseTracking = true;
|
||||||
|
fSelectGranularity = SELECT_LINES;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
TermView::SelectState::MessageReceived(BMessage* message)
|
||||||
|
{
|
||||||
|
if (message->what == kAutoScroll) {
|
||||||
|
_AutoScrollUpdate();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::SelectState::MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message)
|
||||||
|
{
|
||||||
|
if (_StandardMouseMoved(where))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (fCheckMouseTracking) {
|
||||||
|
if (fView->_MouseDistanceSinceLastClick(where) > 9)
|
||||||
|
fMouseTracking = true;
|
||||||
|
}
|
||||||
|
if (!fMouseTracking)
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool doAutoScroll = false;
|
||||||
|
|
||||||
|
if (where.y < 0) {
|
||||||
|
doAutoScroll = true;
|
||||||
|
fView->fAutoScrollSpeed = where.y;
|
||||||
|
where.x = 0;
|
||||||
|
where.y = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
BRect bounds(fView->Bounds());
|
||||||
|
if (where.y > bounds.bottom) {
|
||||||
|
doAutoScroll = true;
|
||||||
|
fView->fAutoScrollSpeed = where.y - bounds.bottom;
|
||||||
|
where.x = bounds.right;
|
||||||
|
where.y = bounds.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (doAutoScroll) {
|
||||||
|
if (fView->fAutoScrollRunner == NULL) {
|
||||||
|
BMessage message(kAutoScroll);
|
||||||
|
fView->fAutoScrollRunner = new (std::nothrow) BMessageRunner(
|
||||||
|
BMessenger(fView), &message, 10000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
delete fView->fAutoScrollRunner;
|
||||||
|
fView->fAutoScrollRunner = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fSelectGranularity) {
|
||||||
|
case SELECT_CHARS:
|
||||||
|
{
|
||||||
|
// If we just start selecting, we first select the initially
|
||||||
|
// hit char, so that we get a proper initial selection -- the char
|
||||||
|
// in question, which will thus always be selected, regardless of
|
||||||
|
// whether selecting forward or backward.
|
||||||
|
if (fView->fInitialSelectionStart == fView->fInitialSelectionEnd) {
|
||||||
|
fView->_Select(fView->fInitialSelectionStart,
|
||||||
|
fView->fInitialSelectionEnd, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
fView->_ExtendSelection(fView->_ConvertToTerminal(where), true,
|
||||||
|
true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SELECT_WORDS:
|
||||||
|
fView->_SelectWord(where, true, true);
|
||||||
|
break;
|
||||||
|
case SELECT_LINES:
|
||||||
|
fView->_SelectLine(where, true, true);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::SelectState::MouseUp(BPoint where, int32 buttons)
|
||||||
|
{
|
||||||
|
fCheckMouseTracking = false;
|
||||||
|
fMouseTracking = false;
|
||||||
|
|
||||||
|
if (fView->fAutoScrollRunner != NULL) {
|
||||||
|
delete fView->fAutoScrollRunner;
|
||||||
|
fView->fAutoScrollRunner = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When releasing the first mouse button, we copy the selected text to the
|
||||||
|
// clipboard.
|
||||||
|
|
||||||
|
if (fView->fReportAnyMouseEvent || fView->fReportButtonMouseEvent
|
||||||
|
|| fView->fReportNormalMouseEvent) {
|
||||||
|
TermPos clickPos = fView->_ConvertToTerminal(where);
|
||||||
|
fView->_SendMouseEvent(0, 0, clickPos.x, clickPos.y, false);
|
||||||
|
} else {
|
||||||
|
if ((buttons & B_PRIMARY_MOUSE_BUTTON) == 0
|
||||||
|
&& (fView->fMouseButtons & B_PRIMARY_MOUSE_BUTTON) != 0) {
|
||||||
|
fView->Copy(fView->fMouseClipboard);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fView->_NextState(fView->fDefaultState);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
TermView::SelectState::_AutoScrollUpdate()
|
||||||
|
{
|
||||||
|
if (fMouseTracking && fView->fAutoScrollRunner != NULL
|
||||||
|
&& fView->fScrollBar != NULL) {
|
||||||
|
float value = fView->fScrollBar->Value();
|
||||||
|
fView->_ScrollTo(value + fView->fAutoScrollSpeed, true);
|
||||||
|
if (fView->fAutoScrollSpeed < 0) {
|
||||||
|
fView->_ExtendSelection(
|
||||||
|
fView->_ConvertToTerminal(BPoint(0, 0)), true, true);
|
||||||
|
} else {
|
||||||
|
fView->_ExtendSelection(
|
||||||
|
fView->_ConvertToTerminal(fView->Bounds().RightBottom()), true,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2001-2013, Haiku, Inc.
|
||||||
|
* Copyright (c) 2003-4 Kian Duffy <myob@users.sourceforge.net>
|
||||||
|
* Parts Copyright (C) 1998,99 Kazuho Okui and Takashi Murai.
|
||||||
|
*
|
||||||
|
* Distributed under the terms of the MIT license.
|
||||||
|
* Authors:
|
||||||
|
* Stefano Ceccherini, stefano.ceccherini@gmail.com
|
||||||
|
* Kian Duffy, myob@users.sourceforge.net
|
||||||
|
* Ingo Weinhold, ingo_weinhold@gmx.de
|
||||||
|
* Siarzhuk Zharski, zharik@gmx.li
|
||||||
|
*/
|
||||||
|
#ifndef TERMVIEW_STATES_H
|
||||||
|
#define TERMVIEW_STATES_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "TermView.h"
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::State {
|
||||||
|
public:
|
||||||
|
State(TermView* view);
|
||||||
|
virtual ~State();
|
||||||
|
|
||||||
|
virtual void Entered();
|
||||||
|
virtual void Exited();
|
||||||
|
|
||||||
|
virtual bool MessageReceived(BMessage* message);
|
||||||
|
// returns true, if handled
|
||||||
|
|
||||||
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, int32 buttons,
|
||||||
|
int32 modifiers);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message);
|
||||||
|
virtual void MouseUp(BPoint where, int32 buttons);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
TermView* fView;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::StandardBaseState : public TermView::State {
|
||||||
|
public:
|
||||||
|
StandardBaseState(TermView* view);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool _StandardMouseMoved(BPoint where);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::DefaultState : public TermView::StandardBaseState {
|
||||||
|
public:
|
||||||
|
DefaultState(TermView* view);
|
||||||
|
|
||||||
|
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||||
|
|
||||||
|
virtual void MouseDown(BPoint where, int32 buttons,
|
||||||
|
int32 modifiers);
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class TermView::SelectState : public TermView::StandardBaseState {
|
||||||
|
public:
|
||||||
|
SelectState(TermView* view);
|
||||||
|
|
||||||
|
void Prepare(BPoint where, int32 modifiers);
|
||||||
|
|
||||||
|
virtual bool MessageReceived(BMessage* message);
|
||||||
|
|
||||||
|
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||||
|
const BMessage* message);
|
||||||
|
virtual void MouseUp(BPoint where, int32 buttons);
|
||||||
|
|
||||||
|
private:
|
||||||
|
void _AutoScrollUpdate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int32 fSelectGranularity;
|
||||||
|
bool fCheckMouseTracking;
|
||||||
|
bool fMouseTracking;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif // TERMVIEW_STATES_H
|
||||||
Reference in New Issue
Block a user