Terminal: Pull user input handling into state classes

This commit is contained in:
Ingo Weinhold
2013-05-11 03:07:30 +02:00
parent a7000a02a0
commit bda35ef5dc
5 changed files with 705 additions and 385 deletions
+1
View File
@@ -33,6 +33,7 @@ Application Terminal :
TermParse.cpp
TermScrollView.cpp
TermView.cpp
TermViewStates.cpp
TermWindow.cpp
TitlePlaceholderMapper.cpp
VTKeyTbl.c
+35 -378
View File
@@ -62,22 +62,13 @@
#include "TermConst.h"
#include "TerminalBuffer.h"
#include "TerminalCharClassifier.h"
#include "TermViewStates.h"
#include "VTkeymap.h"
// defined in VTKeyTbl.c
extern int function_keycode_table[];
extern char *function_key_char_table[];
#define ROWS_DEFAULT 25
#define COLUMNS_DEFAULT 80
// selection granularity
enum {
SELECT_CHARS,
SELECT_WORDS,
SELECT_LINES
};
#undef B_TRANSLATION_CONTEXT
#define B_TRANSLATION_CONTEXT "Terminal TermView"
@@ -101,7 +92,6 @@ static property_info sPropList[] = {
static const uint32 kUpdateSigWinch = 'Rwin';
static const uint32 kBlinkCursor = 'BlCr';
static const uint32 kAutoScroll = 'AScr';
static const bigtime_t kSyncUpdateGranularity = 100000; // 0.1 s
@@ -320,14 +310,15 @@ TermView::_InitObject(const ShellParameters& shellParameters)
fConsiderClockedSync = false;
fSelStart = TermPos(-1, -1);
fSelEnd = TermPos(-1, -1);
fMouseTracking = false;
fCheckMouseTracking = false;
fPrevPos = TermPos(-1, - 1);
fReportX10MouseEvent = false;
fReportNormalMouseEvent = false;
fReportButtonMouseEvent = false;
fReportAnyMouseEvent = false;
fMouseClipboard = be_clipboard;
fDefaultState = new(std::nothrow) DefaultState(this);
fSelectState = new(std::nothrow) SelectState(this);
fActiveState = NULL;
fTextBuffer = new(std::nothrow) TerminalBuffer;
if (fTextBuffer == NULL)
@@ -371,9 +362,14 @@ TermView::_InitObject(const ShellParameters& shellParameters)
if (error < B_OK)
return error;
if (fDefaultState == NULL || fSelectState == NULL)
return B_NO_MEMORY;
SetLowColor(fTextBackColor);
SetViewColor(B_TRANSPARENT_32_BIT);
_NextState(fDefaultState);
return B_OK;
}
@@ -385,6 +381,8 @@ TermView::~TermView()
_DetachShell();
delete fDefaultState;
delete fSelectState;
delete fSyncRunner;
delete fAutoScrollRunner;
delete fCharClassifier;
@@ -1388,165 +1386,7 @@ TermView::MakeFocus(bool focusState)
void
TermView::KeyDown(const char *bytes, int32 numBytes)
{
int32 key, mod, rawChar;
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);
fActiveState->KeyDown(bytes, numBytes);
}
@@ -1593,6 +1433,9 @@ TermView::FrameResized(float width, float height)
void
TermView::MessageReceived(BMessage *msg)
{
if (fActiveState->MessageReceived(msg))
return;
entry_ref ref;
const char *ctrl_l = "\x0c";
@@ -1829,9 +1672,6 @@ TermView::MessageReceived(BMessage *msg)
case kUpdateSigWinch:
_UpdateSIGWINCH();
break;
case kAutoScroll:
_AutoScrollUpdate();
break;
case kSecondaryMouseDropAction:
_DoSecondaryMouseDropAction(msg);
break;
@@ -2480,98 +2320,13 @@ TermView::MouseDown(BPoint where)
if (!IsFocus())
MakeFocus();
int32 buttons;
int32 modifier;
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
Window()->CurrentMessage()->FindInt32("modifiers", &modifier);
BMessage* currentMessage = Window()->CurrentMessage();
int32 buttons = currentMessage->GetInt32("buttons", 0);
int32 modifiers = currentMessage->GetInt32("modifiers", 0);
fActiveState->MouseDown(where, buttons, modifiers);
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;
}
@@ -2579,111 +2334,17 @@ TermView::MouseDown(BPoint where)
void
TermView::MouseMoved(BPoint where, uint32 transit, const BMessage *message)
{
if (fReportAnyMouseEvent || fReportButtonMouseEvent) {
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;
}
fActiveState->MouseMoved(where, transit, message);
}
void
TermView::MouseUp(BPoint where)
{
fCheckMouseTracking = false;
fMouseTracking = false;
int32 buttons = Window()->CurrentMessage()->GetInt32("buttons", 0);
if (fAutoScrollRunner != NULL) {
delete fAutoScrollRunner;
fAutoScrollRunner = NULL;
}
fActiveState->MouseUp(where, buttons);
// 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;
}
@@ -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
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
+18 -7
View File
@@ -143,6 +143,16 @@ protected:
private:
class CharClassifier;
class State;
class StandardBaseState;
class DefaultState;
class SelectState;
friend class State;
friend class StandardBaseState;
friend class DefaultState;
friend class SelectState;
private:
// point and text offset conversion
inline int32 _LineAt(float y);
@@ -199,8 +209,6 @@ private:
void _SelectLine(BPoint where, bool extend,
bool useInitialSelection);
void _AutoScrollUpdate();
bool _CheckSelectedRegion(const TermPos& pos) const;
bool _CheckSelectedRegion(int32 row,
int32 firstColumn, int32& lastColumn) const;
@@ -218,6 +226,8 @@ private:
void _HandleInputMethodLocationRequest();
void _CancelInputMethod();
void _NextState(State* state);
private:
Listener* fListener;
Shell* fShell;
@@ -252,8 +262,6 @@ private:
// Cursor position.
TermPos fCursor;
int32 fMouseButtons;
// Terminal rows and columns.
int fColumns;
int fRows;
@@ -293,18 +301,21 @@ private:
TermPos fSelEnd;
TermPos fInitialSelectionStart;
TermPos fInitialSelectionEnd;
bool fMouseTracking;
bool fCheckMouseTracking;
int fSelectGranularity;
BPoint fLastClickPoint;
// mouse
int32 fMouseButtons;
TermPos fPrevPos;
bool fReportX10MouseEvent;
bool fReportNormalMouseEvent;
bool fReportButtonMouseEvent;
bool fReportAnyMouseEvent;
BClipboard* fMouseClipboard;
// states
DefaultState* fDefaultState;
SelectState* fSelectState;
State* fActiveState;
};
+563
View File
@@ -0,0 +1,563 @@
/*
* Copyright 2001-2013, Haiku, Inc.
* Copyright 2003-2004 Kian Duffy, [email protected]
* Parts Copyright 1998-1999 Kazuho Okui and Takashi Murai.
* All rights reserved. Distributed under the terms of the MIT license.
*
* Authors:
* Stefano Ceccherini, [email protected]
* Kian Duffy, [email protected]
* Y.Hayakawa, [email protected]
* Ingo Weinhold, [email protected]
* Clemens Zeidler, [email protected]
* Siarzhuk Zharski, [email protected]
*/
#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);
}
}
}
+88
View File
@@ -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