diff --git a/src/apps/debugger/files/SourceFile.cpp b/src/apps/debugger/files/SourceFile.cpp index f940717a43..b5ff5f1957 100644 --- a/src/apps/debugger/files/SourceFile.cpp +++ b/src/apps/debugger/files/SourceFile.cpp @@ -98,7 +98,7 @@ SourceFile::Init(const char* path) fLineCount++; // allocate line offset array - fLineOffsets = new(std::nothrow) int32[fLineCount]; + fLineOffsets = new(std::nothrow) int32[fLineCount + 1]; if (fLineOffsets == NULL) return B_NO_MEMORY; @@ -111,6 +111,7 @@ SourceFile::Init(const char* path) fLineOffsets[lineIndex++] = i + 1; } } + fLineOffsets[fLineCount] = fileSize - 1; return B_OK; } @@ -131,6 +132,13 @@ SourceFile::LineAt(int32 index) const } +int32 +SourceFile::LineLengthAt(int32 index) const +{ + return index >= 0 && index < fLineCount + ? fLineOffsets[index + 1] - fLineOffsets[index] - 1: 0; +} + void SourceFile::LastReferenceReleased() { diff --git a/src/apps/debugger/files/SourceFile.h b/src/apps/debugger/files/SourceFile.h index 8b757c9569..fb7bc2da2d 100644 --- a/src/apps/debugger/files/SourceFile.h +++ b/src/apps/debugger/files/SourceFile.h @@ -30,6 +30,7 @@ public: int32 CountLines() const; const char* LineAt(int32 index) const; + int32 LineLengthAt(int32 index) const; protected: virtual void LastReferenceReleased(); diff --git a/src/apps/debugger/gui/team_window/SourceView.cpp b/src/apps/debugger/gui/team_window/SourceView.cpp index 5520b03537..79f9c16cc5 100644 --- a/src/apps/debugger/gui/team_window/SourceView.cpp +++ b/src/apps/debugger/gui/team_window/SourceView.cpp @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -227,10 +228,22 @@ private: offset = _offset; } + bool operator==(const SelectionPoint& other) + { + return line == other.line && offset == other.offset; + } + int32 line; int32 offset; }; + enum TrackingState + { + kNotTracking = 0, + kTracking = 1, + kDragging = 2 + }; + float _MaxLineWidth(); void _FormatLine(const char* line, BString& formattedLine); @@ -238,6 +251,8 @@ private: void _GetSelectionRegion(BRegion& region) const; void _GetSelectionText(BString& text) const; void _CopySelectionToClipboard() const; + void _SelectWordAt(const SelectionPoint& point); + void _SelectLineAt(const SelectionPoint& point); private: @@ -246,8 +261,11 @@ private: SelectionPoint fSelectionStart; SelectionPoint fSelectionEnd; SelectionPoint fSelectionBase; + bigtime_t fLastClickTime; + int16 fClickCount; rgb_color fTextColor; bool fSelectionMode; + TrackingState fTrackState; }; @@ -838,7 +856,10 @@ SourceView::TextView::TextView(SourceView* sourceView, FontInfo* fontInfo) fSelectionStart(-1, -1), fSelectionEnd(-1, -1), fSelectionBase(-1, -1), - fSelectionMode(false) + fLastClickTime(0), + fClickCount(0), + fSelectionMode(false), + fTrackState(kNotTracking) { SetViewColor(ui_color(B_DOCUMENT_BACKGROUND_COLOR)); fTextColor = ui_color(B_DOCUMENT_TEXT_COLOR); @@ -958,8 +979,13 @@ SourceView::TextView::MessageReceived(BMessage* message) _CopySelectionToClipboard(); break; - case B_MOUSE_WHEEL_CHANGED: - fSourceView->MessageReceived(message); + case B_SELECT_ALL: + fSelectionStart.line = 0; + fSelectionStart.offset = 0; + fSelectionEnd.line = fSourceCode->CountLines() - 1; + fSelectionEnd.offset = fSourceCode->LineLengthAt( + fSelectionEnd.line); + Invalidate(); break; default: @@ -975,13 +1001,35 @@ SourceView::TextView::MouseDown(BPoint where) if (fSourceCode != NULL) { if (!IsFocus()) MakeFocus(true); + fTrackState = kTracking; // don't reset the selection if the user clicks within the // current selection range BRegion region; _GetSelectionRegion(region); - if (!region.Contains(where)) { - SelectionPoint point = _SelectionPointAt(where); + bigtime_t clickTime = system_time(); + SelectionPoint point = _SelectionPointAt(where); + bigtime_t clickSpeed = 0; + get_click_speed(&clickSpeed); + if (clickTime - fLastClickTime < clickSpeed + && fSelectionBase == point) { + if (fClickCount > 3) { + fClickCount = 0; + fLastClickTime = 0; + } else { + fClickCount++; + fLastClickTime = clickTime; + } + } else { + fClickCount = 1; + fLastClickTime = clickTime; + } + + if (fClickCount == 2) + _SelectWordAt(point); + else if (fClickCount == 3) { + _SelectLineAt(point); + } else if (!region.Contains(where)) { fSelectionBase = fSelectionStart = fSelectionEnd = point; fSelectionMode = true; Invalidate(); @@ -1023,7 +1071,7 @@ SourceView::TextView::MouseMoved(BPoint where, uint32 transit, _GetSelectionRegion(region); region.Include(&oldRegion); Invalidate(®ion); - } else { + } else if (fTrackState == kTracking) { _GetSelectionRegion(region); if (region.CountRects() > 0) { BString text; @@ -1035,7 +1083,18 @@ SourceView::TextView::MouseMoved(BPoint where, uint32 transit, clipName << " clipping"; message.AddString ("be:clip_name", clipName.String()); message.AddInt32 ("be:actions", B_COPY_TARGET); - DragMessage(&message, region.Frame()); + BRect dragRect = region.Frame(); + BRect visibleRect = fSourceView->Bounds(); + if (dragRect.Height() > visibleRect.Height()) { + dragRect.top = 0; + dragRect.bottom = visibleRect.Height(); + } + if (dragRect.Width() > visibleRect.Width()) { + dragRect.left = 0; + dragRect.right = visibleRect.Width(); + } + DragMessage(&message, dragRect); + fTrackState = kDragging; } } } @@ -1045,6 +1104,7 @@ void SourceView::TextView::MouseUp(BPoint where) { fSelectionMode = false; + fTrackState = kNotTracking; } @@ -1090,7 +1150,7 @@ SourceView::TextView::_SelectionPointAt(BPoint where) const int32 line = LineAtOffset(where.y); int32 offset = (int32)max_c((where.x - kLeftTextMargin) / fCharacterWidth, 0); - int32 lineLength = strlen(fSourceCode->LineAt(line)); + int32 lineLength = fSourceCode->LineLengthAt(line); if (offset > lineLength) offset = (lineLength > 0) ? lineLength - 1 : 0; return SelectionPoint(line, offset); @@ -1184,6 +1244,48 @@ SourceView::TextView::_CopySelectionToClipboard(void) const } +void +SourceView::TextView::_SelectWordAt(const SelectionPoint& point) +{ + const char* line = fSourceCode->LineAt(point.line); + if (isalpha(line[point.offset]) || isdigit(line[point.offset])) { + int32 length = fSourceCode->LineLengthAt(point.line); + int32 start = point.offset - 1; + int32 end = point.offset + 1; + while ((end) < length) { + if (!isalpha(line[end]) && !isdigit(line[end])) + break; + ++end; + } + while ((start - 1) >= 0) { + if (!isalpha(line[start - 1]) && !isdigit(line[start - 1])) + break; + --start; + } + + fSelectionStart.line = point.line; + fSelectionStart.offset = start; + fSelectionEnd.line = point.line; + fSelectionEnd.offset = end; + BRegion region; + _GetSelectionRegion(region); + Invalidate(®ion); + } +} + + +void +SourceView::TextView::_SelectLineAt(const SelectionPoint& point) +{ + fSelectionStart.line = fSelectionEnd.line = point.line; + fSelectionStart.offset = 0; + fSelectionEnd.offset = fSourceCode->LineLengthAt(point.line); + BRegion region; + _GetSelectionRegion(region); + Invalidate(®ion); +} + + // #pragma mark - SourceView diff --git a/src/apps/debugger/gui/team_window/TeamWindow.cpp b/src/apps/debugger/gui/team_window/TeamWindow.cpp index f75cf0d8eb..c93e6aaf34 100644 --- a/src/apps/debugger/gui/team_window/TeamWindow.cpp +++ b/src/apps/debugger/gui/team_window/TeamWindow.cpp @@ -147,6 +147,7 @@ TeamWindow::DispatchMessage(BMessage* message, BHandler* handler) break; case B_COPY: + case B_SELECT_ALL: BView* focusView = CurrentFocus(); if (focusView != NULL) focusView->MessageReceived(message); @@ -413,6 +414,9 @@ TeamWindow::_Init() item = new BMenuItem("Copy", new BMessage(B_COPY), 'C'); menu->AddItem(item); item->SetTarget(this); + item = new BMenuItem("Select All", new BMessage(B_SELECT_ALL), 'A'); + menu->AddItem(item); + item->SetTarget(this); AutoLocker locker(fDebugModel); _UpdateRunButtons(); diff --git a/src/apps/debugger/model/DisassembledCode.cpp b/src/apps/debugger/model/DisassembledCode.cpp index 9f6ebdf65a..7cbbe0c6bf 100644 --- a/src/apps/debugger/model/DisassembledCode.cpp +++ b/src/apps/debugger/model/DisassembledCode.cpp @@ -84,6 +84,14 @@ DisassembledCode::LineAt(int32 index) const } +int32 +DisassembledCode::LineLengthAt(int32 index) const +{ + Line* line = fLines.ItemAt(index); + return line != NULL ? line->line.Length() : 0; +} + + bool DisassembledCode::GetStatementLocationRange(const SourceLocation& location, SourceLocation& _start, SourceLocation& _end) const diff --git a/src/apps/debugger/model/DisassembledCode.h b/src/apps/debugger/model/DisassembledCode.h index 85da92df4b..d1a9dd7357 100644 --- a/src/apps/debugger/model/DisassembledCode.h +++ b/src/apps/debugger/model/DisassembledCode.h @@ -27,6 +27,7 @@ public: virtual int32 CountLines() const; virtual const char* LineAt(int32 index) const; + virtual int32 LineLengthAt(int32 index) const; virtual bool GetStatementLocationRange( const SourceLocation& location, diff --git a/src/apps/debugger/model/FileSourceCode.cpp b/src/apps/debugger/model/FileSourceCode.cpp index 87732e3ac3..792be11497 100644 --- a/src/apps/debugger/model/FileSourceCode.cpp +++ b/src/apps/debugger/model/FileSourceCode.cpp @@ -91,6 +91,13 @@ FileSourceCode::LineAt(int32 index) const } +int32 +FileSourceCode::LineLengthAt(int32 index) const +{ + return fSourceFile->LineLengthAt(index); +} + + bool FileSourceCode::GetStatementLocationRange(const SourceLocation& location, SourceLocation& _start, SourceLocation& _end) const diff --git a/src/apps/debugger/model/FileSourceCode.h b/src/apps/debugger/model/FileSourceCode.h index 03c0d05255..e6a0191fd8 100644 --- a/src/apps/debugger/model/FileSourceCode.h +++ b/src/apps/debugger/model/FileSourceCode.h @@ -35,6 +35,7 @@ public: virtual int32 CountLines() const; virtual const char* LineAt(int32 index) const; + virtual int32 LineLengthAt(int32 index) const; virtual bool GetStatementLocationRange( const SourceLocation& location, diff --git a/src/apps/debugger/model/SourceCode.h b/src/apps/debugger/model/SourceCode.h index aa17d2e93f..1d740115a4 100644 --- a/src/apps/debugger/model/SourceCode.h +++ b/src/apps/debugger/model/SourceCode.h @@ -30,6 +30,7 @@ public: virtual int32 CountLines() const = 0; virtual const char* LineAt(int32 index) const = 0; + virtual int32 LineLengthAt(int32 index) const = 0; virtual bool GetStatementLocationRange( const SourceLocation& location,