[haiku-commits] haiku: hrev46071 - src/apps/debugger/user_interface/gui/inspector_window

  • From: anevilyak@xxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Mon, 16 Sep 2013 19:48:19 +0200 (CEST)

hrev46071 adds 1 changeset to branch 'master'
old head: 29fdf5e8aed6e54ff039ffecf4abb8a77897b836
new head: 6c5893fbbf22dfc58f622c244ee09a718f89ad43
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=6c5893f+%5E29fdf5e

----------------------------------------------------------------------------

6c5893f: Debugger: Add selection support to MemoryView.
  
  - The Inspector's memory view now supports selecting chunks of the hex 
display in
    the manner one would in a TextView. The selection can also be copied to the 
clipboard,
    or if it matches the size of a target address, can be used as input for an 
address to
    inspect directly.
  
  Still needs some fine tuning, but basically works.

                                      [ Rene Gollent <anevilyak@xxxxxxxxx> ]

----------------------------------------------------------------------------

Revision:    hrev46071
Commit:      6c5893fbbf22dfc58f622c244ee09a718f89ad43
URL:         http://cgit.haiku-os.org/haiku/commit/?id=6c5893f
Author:      Rene Gollent <anevilyak@xxxxxxxxx>
Date:        Mon Sep 16 17:45:27 2013 UTC

----------------------------------------------------------------------------

2 files changed, 442 insertions(+), 35 deletions(-)
.../gui/inspector_window/MemoryView.cpp          | 443 +++++++++++++++++--
.../gui/inspector_window/MemoryView.h            |  34 +-

----------------------------------------------------------------------------

diff --git 
a/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.cpp 
b/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.cpp
index a59e967..c00e38a 100644
--- a/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.cpp
+++ b/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.cpp
@@ -11,20 +11,30 @@
 #include <stdio.h>
 
 #include <ByteOrder.h>
+#include <Clipboard.h>
 #include <Looper.h>
+#include <MenuItem.h>
+#include <MessageRunner.h>
 #include <Messenger.h>
+#include <PopUpMenu.h>
+#include <Region.h>
 #include <ScrollView.h>
 #include <String.h>
 
 #include "Architecture.h"
+#include "AutoDeleter.h"
+#include "MessageCodes.h"
 #include "Team.h"
 #include "TeamMemoryBlock.h"
 
 
 enum {
-       MSG_TARGET_ADDRESS_CHANGED = 'mtac'
+       MSG_TARGET_ADDRESS_CHANGED = 'mtac',
+       MSG_VIEW_AUTOSCROLL                     = 'mvas'
 };
 
+static const bigtime_t kScrollTimer = 10000LL;
+
 
 MemoryView::MemoryView(::Team* team, Listener* listener)
        :
@@ -39,6 +49,10 @@ MemoryView::MemoryView(::Team* team, Listener* listener)
        fHexBlocksPerLine(0),
        fHexMode(HexMode8BitInt),
        fTextMode(TextModeASCII),
+       fSelectionBase(0),
+       fSelectionStart(0),
+       fSelectionEnd(0),
+       fScrollRunner(NULL),
        fListener(listener)
 {
        Architecture* architecture = team->GetArchitecture();
@@ -76,11 +90,14 @@ void
 MemoryView::SetTargetAddress(TeamMemoryBlock* block, target_addr_t address)
 {
        fTargetAddress = address;
-       if (fTargetBlock != NULL)
+       if (block != fTargetBlock && fTargetBlock != NULL)
                fTargetBlock->ReleaseReference();
 
-       fTargetBlock = block;
-       fTargetBlock->AcquireReference();
+       if (block != fTargetBlock) {
+               fTargetBlock = block;
+               fTargetBlock->AcquireReference();
+       }
+
        MakeFocus(true);
        BMessenger(this).SendMessage(MSG_TARGET_ADDRESS_CHANGED);
 }
@@ -119,7 +136,7 @@ MemoryView::Draw(BRect rect)
        if (fTargetBlock == NULL)
                return;
 
-       uint32 hexBlockSize = (1 << fHexMode) + 1;
+       uint32 hexBlockSize = _GetHexDigitsPerBlock() + 1;
        uint32 blockByteSize = hexBlockSize / 2;
        if (fHexMode != HexModeNone && fTextMode != TextModeNone) {
                divider += (fHexBlocksPerLine * hexBlockSize + 1) * fCharWidth;
@@ -156,7 +173,6 @@ MemoryView::Draw(BRect rect)
                DrawString(buffer, drawPoint);
                drawPoint.x += fCharWidth * (fTargetAddressSize + 2);
                PopState();
-
                if (fHexMode != HexModeNone) {
                        if (currentAddress + (currentBlocksPerLine * 
blockByteSize)
                                > maxAddress) {
@@ -190,6 +206,7 @@ MemoryView::Draw(BRect rect)
                                drawPoint.x += fCharWidth * hexBlockSize
                                        * (fHexBlocksPerLine - 
currentBlocksPerLine);
                }
+
                if (fTextMode != TextModeNone) {
                        drawPoint.x += fCharWidth;
                        for (int32 j = 0; j < currentCharsPerLine; j++) {
@@ -226,6 +243,15 @@ MemoryView::Draw(BRect rect)
                        lineAddress += fTextCharsPerLine;
                }
        }
+
+       if (fSelectionStart != fSelectionEnd) {
+               PushState();
+               BRegion selectionRegion;
+               _GetSelectionRegion(selectionRegion);
+               SetDrawingMode(B_OP_INVERT);
+               FillRegion(&selectionRegion, B_SOLID_HIGH);
+               PopState();
+       }
 }
 
 
@@ -332,6 +358,11 @@ void
 MemoryView::MessageReceived(BMessage* message)
 {
        switch(message->what) {
+               case B_COPY:
+               {
+                       _CopySelectionToClipboard();
+                       break;
+               }
                case MSG_TARGET_ADDRESS_CHANGED:
                {
                        _RecalcScrollBars();
@@ -370,6 +401,11 @@ MemoryView::MessageReceived(BMessage* message)
                        }
                        break;
                }
+               case MSG_VIEW_AUTOSCROLL:
+               {
+                       _HandleAutoScroll();
+                       break;
+               }
                default:
                {
                        BView::MessageReceived(message);
@@ -385,7 +421,78 @@ MemoryView::MouseDown(BPoint point)
        if (!IsFocus())
                MakeFocus(true);
 
-       BView::MouseDown(point);
+       if (fTargetBlock == NULL)
+               return;
+
+       int32 buttons;
+       if (Looper()->CurrentMessage()->FindInt32("buttons", &buttons) != B_OK)
+               buttons = B_PRIMARY_MOUSE_BUTTON;
+
+       if (buttons == B_SECONDARY_MOUSE_BUTTON) {
+               _HandleContextMenu(point);
+               return;
+       }
+
+       int32 offset = _GetOffsetAt(point);
+       if (offset < fSelectionStart || offset > fSelectionEnd) {
+               BRegion oldSelectionRegion;
+               _GetSelectionRegion(oldSelectionRegion);
+               fSelectionBase = offset;
+               fSelectionStart = fSelectionBase;
+               fSelectionEnd = fSelectionBase;
+               Invalidate(oldSelectionRegion.Frame());
+       }
+
+       SetMouseEventMask(B_POINTER_EVENTS, B_NO_POINTER_HISTORY);
+       fTrackingMouse = true;
+}
+
+
+void
+MemoryView::MouseMoved(BPoint point, uint32 transit, const BMessage* message)
+{
+       if (!fTrackingMouse)
+               return;
+
+       BRegion oldSelectionRegion;
+       _GetSelectionRegion(oldSelectionRegion);
+       int32 offset = _GetOffsetAt(point);
+       if (offset < fSelectionBase) {
+               fSelectionStart = offset;
+               fSelectionEnd = fSelectionBase;
+       } else {
+               fSelectionStart = fSelectionBase;
+               fSelectionEnd = offset;
+       }
+
+       BRegion region;
+       _GetSelectionRegion(region);
+       region.Include(&oldSelectionRegion);
+       Invalidate(region.Frame());
+
+       switch (transit) {
+               case B_EXITED_VIEW:
+                       fScrollRunner = new BMessageRunner(BMessenger(this),
+                               new BMessage(MSG_VIEW_AUTOSCROLL), 
kScrollTimer);
+                       break;
+
+               case B_ENTERED_VIEW:
+                       delete fScrollRunner;
+                       fScrollRunner = NULL;
+                       break;
+
+               default:
+                       break;
+       }
+}
+
+
+void
+MemoryView::MouseUp(BPoint point)
+{
+       fTrackingMouse = false;
+       delete fScrollRunner;
+       fScrollRunner = NULL;
 }
 
 
@@ -395,10 +502,12 @@ MemoryView::ScrollToSelection()
        if (fTargetBlock != NULL) {
                target_addr_t offset = fTargetAddress - 
fTargetBlock->BaseAddress();
                int32 lineNumber = 0;
-               if (fHexBlocksPerLine > 0)
-                       lineNumber = offset / (fHexBlocksPerLine * (1 << 
(fHexMode - 1)));
-               else if (fTextCharsPerLine > 0)
+               if (fHexBlocksPerLine > 0) {
+                       lineNumber = offset / (fHexBlocksPerLine
+                               * (_GetHexDigitsPerBlock() / 2));
+               } else if (fTextCharsPerLine > 0)
                        lineNumber = offset / fTextCharsPerLine;
+
                float y = lineNumber * fLineHeight;
                if (y < Bounds().top)
                        ScrollTo(0.0, y);
@@ -429,40 +538,23 @@ MemoryView::_RecalcScrollBars()
        float max = 0.0;
        BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
        if (fTargetBlock != NULL) {
-               BRect bounds = Bounds();
-               // the left portion of the view is off limits since it
-               // houses the address offset of the current line
-               float baseWidth = bounds.Width() - ((fTargetAddressSize + 2)
-                       * fCharWidth);
-               float hexWidth = 0.0;
-               float textWidth = 0.0;
-               int32 hexDigits = 1 << fHexMode;
+               int32 hexDigits = _GetHexDigitsPerBlock();
                int32 sizeFactor = 1 + hexDigits;
-               if (fHexMode != HexModeNone) {
-                       if (fTextMode != TextModeNone) {
-                               float hexProportion = sizeFactor / 
(float)(sizeFactor
-                                       + hexDigits / 2);
-                               hexWidth = baseWidth * hexProportion;
-                               // when sharing the display between hex and 
text,
-                               // we allocate a 2 character space to separate 
the views
-                               hexWidth -= 2 * fCharWidth;
-                               textWidth = baseWidth - hexWidth;
-                       } else
-                               hexWidth = baseWidth;
-               } else if (fTextMode != TextModeNone)
-                       textWidth = baseWidth;
+               _RecalcBounds();
 
+               float hexWidth = fHexRight - fHexLeft;
                int32 nybblesPerLine = int32(hexWidth / fCharWidth);
                fHexBlocksPerLine = 0;
                fTextCharsPerLine = 0;
                if (fHexMode != HexModeNone) {
                        fHexBlocksPerLine = nybblesPerLine / sizeFactor;
                        fHexBlocksPerLine &= ~1;
+                       fHexRight = fHexLeft + (fHexBlocksPerLine * sizeFactor
+                               * fCharWidth);
                        if (fTextMode != TextModeNone)
                                fTextCharsPerLine = fHexBlocksPerLine * 
hexDigits / 2;
                } else if (fTextMode != TextModeNone)
-                       fTextCharsPerLine = int32(textWidth / fCharWidth);
-
+                       fTextCharsPerLine = int32((fTextRight - fTextLeft) / 
fCharWidth);
                int32 lineCount = 0;
                float totalHeight = 0.0;
                if (fHexBlocksPerLine > 0) {
@@ -473,6 +565,7 @@ MemoryView::_RecalcScrollBars()
 
                totalHeight = lineCount * fLineHeight;
                if (totalHeight > 0.0) {
+                       BRect bounds = Bounds();
                        max = totalHeight - bounds.Height();
                        scrollBar->SetProportion(bounds.Height() / totalHeight);
                        scrollBar->SetSteps(fLineHeight, bounds.Height());
@@ -558,6 +651,290 @@ MemoryView::_GetNextHexBlock(char* buffer, int32 
bufferSize,
 }
 
 
+int32
+MemoryView::_GetOffsetAt(BPoint point) const
+{
+       if (fTargetBlock == NULL)
+               return -1;
+
+       // TODO: support selection in the text region as well
+       if (fHexMode == HexModeNone)
+               return -1;
+
+       int32 lineNumber = point.y / fLineHeight;
+       int32 charsPerBlock = _GetHexDigitsPerBlock() / 2;
+       int32 totalHexBlocks = fTargetBlock->Size() / charsPerBlock;
+       int32 lineCount = totalHexBlocks / fHexBlocksPerLine;
+
+       if (lineNumber >= lineCount)
+               return -1;
+
+       point.x -= fHexLeft;
+       if (point.x < 0)
+               point.x = 0;
+       else if (point.x > fHexRight)
+               point.x = fHexRight;
+
+       float blockWidth = (charsPerBlock * 2 + 1) * fCharWidth;
+       int32 containingBlock = int32(floor(point.x / blockWidth));
+
+       return fHexBlocksPerLine * lineNumber
+               + containingBlock * charsPerBlock;
+}
+
+
+BPoint
+MemoryView::_GetPointForOffset(int32 offset) const
+{
+       BPoint point;
+       int32 bytesPerLine = fHexBlocksPerLine * _GetHexDigitsPerBlock() / 2;
+       int32 line = offset / bytesPerLine;
+       int32 lineOffset = offset % bytesPerLine;
+
+       point.x = fHexLeft + (lineOffset * 2 * fCharWidth)
+                       + (lineOffset * 2 * fCharWidth / 
_GetHexDigitsPerBlock());
+       point.y = line * fLineHeight;
+
+       return point;
+}
+
+
+void
+MemoryView::_RecalcBounds()
+{
+       fHexLeft = 0;
+       fHexRight = 0;
+       fTextLeft = 0;
+       fTextRight = 0;
+
+       // the left bound is determined by the space taken up by the actual
+       // displayed addresses.
+       float left = _GetAddressDisplayWidth();
+       float width = Bounds().Width() - left;
+
+       if (fHexMode != HexModeNone) {
+               int32 hexDigits = _GetHexDigitsPerBlock();
+               int32 sizeFactor = 1 + hexDigits;
+               if (fTextMode != TextModeNone) {
+                       float hexProportion = sizeFactor / (float)(sizeFactor
+                               + hexDigits / 2);
+                       float hexWidth = width * hexProportion;
+                       fTextLeft = left + hexWidth;
+                       fHexLeft = left;
+                       // when sharing the display between hex and text,
+                       // we allocate a 2 character space to separate the views
+                       hexWidth -= 2 * fCharWidth;
+                       fHexRight = left + hexWidth;
+               } else {
+                       fHexLeft = left;
+                       fHexRight = left + width;
+               }
+       } else if (fTextMode != TextModeNone) {
+               fTextLeft = left;
+               fTextRight = left + width;
+       }
+}
+
+
+float
+MemoryView::_GetAddressDisplayWidth() const
+{
+       return (fTargetAddressSize + 2) * fCharWidth;
+}
+
+
+void
+MemoryView::_GetSelectionRegion(BRegion& region)
+{
+       region.MakeEmpty();
+       BPoint startPoint = _GetPointForOffset(fSelectionStart);
+       BPoint endPoint = _GetPointForOffset(fSelectionEnd);
+
+       BRect rect;
+       if (startPoint.y == endPoint.y) {
+               // single line case
+               rect.left = startPoint.x;
+               rect.top = startPoint.y;
+               rect.right = endPoint.x;
+               rect.bottom = endPoint.y + fLineHeight;
+               region.Include(rect);
+       } else {
+               float currentLine = startPoint.y;
+
+               // first line
+               rect.left = startPoint.x;
+               rect.top = startPoint.y;
+               rect.right = fHexRight;
+               rect.bottom = startPoint.y + fLineHeight;
+               region.Include(rect);
+               currentLine += fLineHeight;
+
+               // middle region
+               if (currentLine < endPoint.y) {
+                       rect.left = fHexLeft;
+                       rect.top = currentLine;
+                       rect.right = fHexRight;
+                       rect.bottom = endPoint.y;
+                       region.Include(rect);
+               }
+
+               rect.left = fHexLeft;
+               rect.top = endPoint.y;
+               rect.right = endPoint.x;
+               rect.bottom = endPoint.y + fLineHeight;
+               region.Include(rect);
+       }
+}
+
+
+void
+MemoryView::_GetSelectedText(BString& text)
+{
+       if (fSelectionStart == fSelectionEnd)
+               return;
+
+       text.Truncate(0);
+
+       char* data = (char *)fTargetBlock->Data() + fSelectionStart;
+       int16 blockSize = _GetHexDigitsPerBlock() / 2;
+       int32 count = (fSelectionEnd - fSelectionStart)
+               / blockSize;
+
+       char buffer[32];
+       for (int32 i = 0; i < count; i++) {
+               _GetNextHexBlock(buffer, sizeof(buffer), data);
+               data += blockSize;
+               text << buffer;
+               if (i < count - 1)
+                       text << " ";
+       }
+}
+
+
+void
+MemoryView::_CopySelectionToClipboard()
+{
+       BString text;
+       _GetSelectedText(text);
+
+       if (text.Length() > 0) {
+               be_clipboard->Lock();
+               be_clipboard->Data()->RemoveData("text/plain");
+               be_clipboard->Data()->AddData ("text/plain",
+                       B_MIME_TYPE, text.String(), text.Length());
+               be_clipboard->Commit();
+               be_clipboard->Unlock();
+       }
+}
+
+
+void
+MemoryView::_HandleAutoScroll()
+{
+       BPoint point;
+       uint32 buttons;
+       GetMouse(&point, &buttons);
+       float difference = 0.0;
+       int factor = 0;
+       BRect visibleRect = Bounds();
+       if (point.y < visibleRect.top)
+               difference = point.y - visibleRect.top;
+       else if (point.y > visibleRect.bottom)
+               difference = point.y - visibleRect.bottom;
+       if (difference != 0.0) {
+               factor = (int)(ceilf(difference / fLineHeight));
+               _ScrollByLines(factor);
+       }
+
+       MouseMoved(point, B_OUTSIDE_VIEW, NULL);
+}
+
+
+void
+MemoryView::_ScrollByLines(int32 lineCount)
+{
+       BScrollBar* vertical = ScrollBar(B_VERTICAL);
+       if (vertical == NULL)
+               return;
+
+       float value = vertical->Value();
+       vertical->SetValue(value + fLineHeight * lineCount);
+}
+
+
+void
+MemoryView::_HandleContextMenu(BPoint point)
+{
+       int32 offset = _GetOffsetAt(point);
+       if (offset < fSelectionStart || offset > fSelectionEnd)
+               return;
+
+       BPopUpMenu* menu = new(std::nothrow) BPopUpMenu("Options");
+       if (menu == NULL)
+               return;
+
+       ObjectDeleter<BPopUpMenu> menuDeleter(menu);
+       ObjectDeleter<BMenuItem> itemDeleter;
+       ObjectDeleter<BMessage> messageDeleter;
+       BMessage* message = NULL;
+       BMenuItem* item = NULL;
+       if (fSelectionEnd - fSelectionStart == fTargetAddressSize / 2) {
+               BMessage* message = new(std::nothrow) 
BMessage(MSG_INSPECT_ADDRESS);
+               if (message == NULL)
+                       return;
+
+               target_addr_t address;
+               if (fTargetAddressSize == 8)
+                       address = *((uint32*)(fTargetBlock->Data() + 
fSelectionStart));
+               else
+                       address = *((uint64*)(fTargetBlock->Data() + 
fSelectionStart));
+
+               if (fEndianMode == EndianModeBigEndian)
+                       address = B_HOST_TO_BENDIAN_INT64(address);
+               else
+                       address = B_HOST_TO_LENDIAN_INT64(address);
+
+               messageDeleter.SetTo(message);
+               message->AddUInt64("address", address);
+               BMenuItem* item = new(std::nothrow) BMenuItem("Inspect", 
message);
+               if (item == NULL)
+                       return;
+
+               messageDeleter.Detach();
+               itemDeleter.SetTo(item);
+               if (!menu->AddItem(item))
+                       return;
+
+               item->SetTarget(Looper());
+               itemDeleter.Detach();
+       }
+
+       message = new(std::nothrow) BMessage(B_COPY);
+       if (message == NULL)
+               return;
+
+       messageDeleter.SetTo(message);
+       item = new(std::nothrow) BMenuItem("Copy", message);
+       if (item == NULL)
+               return;
+
+       messageDeleter.Detach();
+       itemDeleter.SetTo(item);
+       if (!menu->AddItem(item))
+               return;
+
+       item->SetTarget(this);
+       itemDeleter.Detach();
+       menuDeleter.Detach();
+
+       BPoint screenWhere(point);
+       ConvertToScreen(&screenWhere);
+       BRect mouseRect(screenWhere, screenWhere);
+       mouseRect.InsetBy(-4.0, -4.0);
+       menu->Go(screenWhere, true, false, mouseRect, true);
+}
+
+
 //#pragma mark - Listener
 
 
diff --git a/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.h 
b/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.h
index ca10a25..9731971 100644
--- a/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.h
+++ b/src/apps/debugger/user_interface/gui/inspector_window/MemoryView.h
@@ -38,9 +38,9 @@ enum {
 };
 
 
-class Team;
-
+class BMessageRunner;
 
+class Team;
 class TeamMemoryBlock;
 
 
@@ -66,6 +66,9 @@ public:
        virtual void                            MakeFocus(bool isFocused);
        virtual void                            MessageReceived(BMessage* 
message);
        virtual void                            MouseDown(BPoint point);
+       virtual void                            MouseMoved(BPoint point, uint32 
transit,
+                                                                       const 
BMessage* dragMessage);
+       virtual void                            MouseUp(BPoint point);
                        void                            ScrollToSelection();
        virtual void                            
TargetedByScrollView(BScrollView* scrollView);
 
@@ -75,6 +78,22 @@ private:
        void                                            _GetNextHexBlock(char* 
buffer,
                                                                        int32 
bufferSize, const char* address);
 
+       int32                                           _GetOffsetAt(BPoint 
point) const;
+       BPoint                                          
_GetPointForOffset(int32 offset) const;
+       void                                            _RecalcBounds();
+       float                                           
_GetAddressDisplayWidth() const;
+
+       inline int32                            _GetHexDigitsPerBlock() const
+                                                                       { 
return 1 << fHexMode; };
+
+       void                                            
_GetSelectionRegion(BRegion& region);
+       void                                            
_GetSelectedText(BString& text);
+       void                                            
_CopySelectionToClipboard();
+
+       void                                            _HandleAutoScroll();
+       void                                            _ScrollByLines(int32 
lineCount);
+       void                                            
_HandleContextMenu(BPoint point);
+
 private:
        ::Team*                                         fTeam;
        TeamMemoryBlock*                        fTargetBlock;
@@ -87,6 +106,17 @@ private:
        int32                                           fCurrentEndianMode;
        int32                                           fHexMode;
        int32                                           fTextMode;
+       float                                           fHexLeft;
+       float                                           fHexRight;
+       float                                           fTextLeft;
+       float                                           fTextRight;
+       int32                                           fSelectionBase;
+       int32                                           fSelectionStart;
+       int32                                           fSelectionEnd;
+       BMessageRunner*                         fScrollRunner;
+
+       bool                                            fTrackingMouse;
+
        Listener*                                       fListener;
 };
 


Other related posts:

  • » [haiku-commits] haiku: hrev46071 - src/apps/debugger/user_interface/gui/inspector_window - anevilyak