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.
This commit is contained in:
@@ -11,20 +11,30 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include <ByteOrder.h>
|
#include <ByteOrder.h>
|
||||||
|
#include <Clipboard.h>
|
||||||
#include <Looper.h>
|
#include <Looper.h>
|
||||||
|
#include <MenuItem.h>
|
||||||
|
#include <MessageRunner.h>
|
||||||
#include <Messenger.h>
|
#include <Messenger.h>
|
||||||
|
#include <PopUpMenu.h>
|
||||||
|
#include <Region.h>
|
||||||
#include <ScrollView.h>
|
#include <ScrollView.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include "Architecture.h"
|
#include "Architecture.h"
|
||||||
|
#include "AutoDeleter.h"
|
||||||
|
#include "MessageCodes.h"
|
||||||
#include "Team.h"
|
#include "Team.h"
|
||||||
#include "TeamMemoryBlock.h"
|
#include "TeamMemoryBlock.h"
|
||||||
|
|
||||||
|
|
||||||
enum {
|
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)
|
MemoryView::MemoryView(::Team* team, Listener* listener)
|
||||||
:
|
:
|
||||||
@@ -39,6 +49,10 @@ MemoryView::MemoryView(::Team* team, Listener* listener)
|
|||||||
fHexBlocksPerLine(0),
|
fHexBlocksPerLine(0),
|
||||||
fHexMode(HexMode8BitInt),
|
fHexMode(HexMode8BitInt),
|
||||||
fTextMode(TextModeASCII),
|
fTextMode(TextModeASCII),
|
||||||
|
fSelectionBase(0),
|
||||||
|
fSelectionStart(0),
|
||||||
|
fSelectionEnd(0),
|
||||||
|
fScrollRunner(NULL),
|
||||||
fListener(listener)
|
fListener(listener)
|
||||||
{
|
{
|
||||||
Architecture* architecture = team->GetArchitecture();
|
Architecture* architecture = team->GetArchitecture();
|
||||||
@@ -76,11 +90,14 @@ void
|
|||||||
MemoryView::SetTargetAddress(TeamMemoryBlock* block, target_addr_t address)
|
MemoryView::SetTargetAddress(TeamMemoryBlock* block, target_addr_t address)
|
||||||
{
|
{
|
||||||
fTargetAddress = address;
|
fTargetAddress = address;
|
||||||
if (fTargetBlock != NULL)
|
if (block != fTargetBlock && fTargetBlock != NULL)
|
||||||
fTargetBlock->ReleaseReference();
|
fTargetBlock->ReleaseReference();
|
||||||
|
|
||||||
fTargetBlock = block;
|
if (block != fTargetBlock) {
|
||||||
fTargetBlock->AcquireReference();
|
fTargetBlock = block;
|
||||||
|
fTargetBlock->AcquireReference();
|
||||||
|
}
|
||||||
|
|
||||||
MakeFocus(true);
|
MakeFocus(true);
|
||||||
BMessenger(this).SendMessage(MSG_TARGET_ADDRESS_CHANGED);
|
BMessenger(this).SendMessage(MSG_TARGET_ADDRESS_CHANGED);
|
||||||
}
|
}
|
||||||
@@ -119,7 +136,7 @@ MemoryView::Draw(BRect rect)
|
|||||||
if (fTargetBlock == NULL)
|
if (fTargetBlock == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32 hexBlockSize = (1 << fHexMode) + 1;
|
uint32 hexBlockSize = _GetHexDigitsPerBlock() + 1;
|
||||||
uint32 blockByteSize = hexBlockSize / 2;
|
uint32 blockByteSize = hexBlockSize / 2;
|
||||||
if (fHexMode != HexModeNone && fTextMode != TextModeNone) {
|
if (fHexMode != HexModeNone && fTextMode != TextModeNone) {
|
||||||
divider += (fHexBlocksPerLine * hexBlockSize + 1) * fCharWidth;
|
divider += (fHexBlocksPerLine * hexBlockSize + 1) * fCharWidth;
|
||||||
@@ -156,7 +173,6 @@ MemoryView::Draw(BRect rect)
|
|||||||
DrawString(buffer, drawPoint);
|
DrawString(buffer, drawPoint);
|
||||||
drawPoint.x += fCharWidth * (fTargetAddressSize + 2);
|
drawPoint.x += fCharWidth * (fTargetAddressSize + 2);
|
||||||
PopState();
|
PopState();
|
||||||
|
|
||||||
if (fHexMode != HexModeNone) {
|
if (fHexMode != HexModeNone) {
|
||||||
if (currentAddress + (currentBlocksPerLine * blockByteSize)
|
if (currentAddress + (currentBlocksPerLine * blockByteSize)
|
||||||
> maxAddress) {
|
> maxAddress) {
|
||||||
@@ -190,6 +206,7 @@ MemoryView::Draw(BRect rect)
|
|||||||
drawPoint.x += fCharWidth * hexBlockSize
|
drawPoint.x += fCharWidth * hexBlockSize
|
||||||
* (fHexBlocksPerLine - currentBlocksPerLine);
|
* (fHexBlocksPerLine - currentBlocksPerLine);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fTextMode != TextModeNone) {
|
if (fTextMode != TextModeNone) {
|
||||||
drawPoint.x += fCharWidth;
|
drawPoint.x += fCharWidth;
|
||||||
for (int32 j = 0; j < currentCharsPerLine; j++) {
|
for (int32 j = 0; j < currentCharsPerLine; j++) {
|
||||||
@@ -226,6 +243,15 @@ MemoryView::Draw(BRect rect)
|
|||||||
lineAddress += fTextCharsPerLine;
|
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)
|
MemoryView::MessageReceived(BMessage* message)
|
||||||
{
|
{
|
||||||
switch(message->what) {
|
switch(message->what) {
|
||||||
|
case B_COPY:
|
||||||
|
{
|
||||||
|
_CopySelectionToClipboard();
|
||||||
|
break;
|
||||||
|
}
|
||||||
case MSG_TARGET_ADDRESS_CHANGED:
|
case MSG_TARGET_ADDRESS_CHANGED:
|
||||||
{
|
{
|
||||||
_RecalcScrollBars();
|
_RecalcScrollBars();
|
||||||
@@ -370,6 +401,11 @@ MemoryView::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MSG_VIEW_AUTOSCROLL:
|
||||||
|
{
|
||||||
|
_HandleAutoScroll();
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
BView::MessageReceived(message);
|
BView::MessageReceived(message);
|
||||||
@@ -385,7 +421,78 @@ MemoryView::MouseDown(BPoint point)
|
|||||||
if (!IsFocus())
|
if (!IsFocus())
|
||||||
MakeFocus(true);
|
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) {
|
if (fTargetBlock != NULL) {
|
||||||
target_addr_t offset = fTargetAddress - fTargetBlock->BaseAddress();
|
target_addr_t offset = fTargetAddress - fTargetBlock->BaseAddress();
|
||||||
int32 lineNumber = 0;
|
int32 lineNumber = 0;
|
||||||
if (fHexBlocksPerLine > 0)
|
if (fHexBlocksPerLine > 0) {
|
||||||
lineNumber = offset / (fHexBlocksPerLine * (1 << (fHexMode - 1)));
|
lineNumber = offset / (fHexBlocksPerLine
|
||||||
else if (fTextCharsPerLine > 0)
|
* (_GetHexDigitsPerBlock() / 2));
|
||||||
|
} else if (fTextCharsPerLine > 0)
|
||||||
lineNumber = offset / fTextCharsPerLine;
|
lineNumber = offset / fTextCharsPerLine;
|
||||||
|
|
||||||
float y = lineNumber * fLineHeight;
|
float y = lineNumber * fLineHeight;
|
||||||
if (y < Bounds().top)
|
if (y < Bounds().top)
|
||||||
ScrollTo(0.0, y);
|
ScrollTo(0.0, y);
|
||||||
@@ -429,40 +538,23 @@ MemoryView::_RecalcScrollBars()
|
|||||||
float max = 0.0;
|
float max = 0.0;
|
||||||
BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
|
BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
|
||||||
if (fTargetBlock != NULL) {
|
if (fTargetBlock != NULL) {
|
||||||
BRect bounds = Bounds();
|
int32 hexDigits = _GetHexDigitsPerBlock();
|
||||||
// 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 sizeFactor = 1 + hexDigits;
|
int32 sizeFactor = 1 + hexDigits;
|
||||||
if (fHexMode != HexModeNone) {
|
_RecalcBounds();
|
||||||
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;
|
|
||||||
|
|
||||||
|
float hexWidth = fHexRight - fHexLeft;
|
||||||
int32 nybblesPerLine = int32(hexWidth / fCharWidth);
|
int32 nybblesPerLine = int32(hexWidth / fCharWidth);
|
||||||
fHexBlocksPerLine = 0;
|
fHexBlocksPerLine = 0;
|
||||||
fTextCharsPerLine = 0;
|
fTextCharsPerLine = 0;
|
||||||
if (fHexMode != HexModeNone) {
|
if (fHexMode != HexModeNone) {
|
||||||
fHexBlocksPerLine = nybblesPerLine / sizeFactor;
|
fHexBlocksPerLine = nybblesPerLine / sizeFactor;
|
||||||
fHexBlocksPerLine &= ~1;
|
fHexBlocksPerLine &= ~1;
|
||||||
|
fHexRight = fHexLeft + (fHexBlocksPerLine * sizeFactor
|
||||||
|
* fCharWidth);
|
||||||
if (fTextMode != TextModeNone)
|
if (fTextMode != TextModeNone)
|
||||||
fTextCharsPerLine = fHexBlocksPerLine * hexDigits / 2;
|
fTextCharsPerLine = fHexBlocksPerLine * hexDigits / 2;
|
||||||
} else if (fTextMode != TextModeNone)
|
} else if (fTextMode != TextModeNone)
|
||||||
fTextCharsPerLine = int32(textWidth / fCharWidth);
|
fTextCharsPerLine = int32((fTextRight - fTextLeft) / fCharWidth);
|
||||||
|
|
||||||
int32 lineCount = 0;
|
int32 lineCount = 0;
|
||||||
float totalHeight = 0.0;
|
float totalHeight = 0.0;
|
||||||
if (fHexBlocksPerLine > 0) {
|
if (fHexBlocksPerLine > 0) {
|
||||||
@@ -473,6 +565,7 @@ MemoryView::_RecalcScrollBars()
|
|||||||
|
|
||||||
totalHeight = lineCount * fLineHeight;
|
totalHeight = lineCount * fLineHeight;
|
||||||
if (totalHeight > 0.0) {
|
if (totalHeight > 0.0) {
|
||||||
|
BRect bounds = Bounds();
|
||||||
max = totalHeight - bounds.Height();
|
max = totalHeight - bounds.Height();
|
||||||
scrollBar->SetProportion(bounds.Height() / totalHeight);
|
scrollBar->SetProportion(bounds.Height() / totalHeight);
|
||||||
scrollBar->SetSteps(fLineHeight, bounds.Height());
|
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
|
//#pragma mark - Listener
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class BMessageRunner;
|
||||||
|
|
||||||
class Team;
|
class Team;
|
||||||
|
|
||||||
|
|
||||||
class TeamMemoryBlock;
|
class TeamMemoryBlock;
|
||||||
|
|
||||||
|
|
||||||
@@ -66,6 +66,9 @@ public:
|
|||||||
virtual void MakeFocus(bool isFocused);
|
virtual void MakeFocus(bool isFocused);
|
||||||
virtual void MessageReceived(BMessage* message);
|
virtual void MessageReceived(BMessage* message);
|
||||||
virtual void MouseDown(BPoint point);
|
virtual void MouseDown(BPoint point);
|
||||||
|
virtual void MouseMoved(BPoint point, uint32 transit,
|
||||||
|
const BMessage* dragMessage);
|
||||||
|
virtual void MouseUp(BPoint point);
|
||||||
void ScrollToSelection();
|
void ScrollToSelection();
|
||||||
virtual void TargetedByScrollView(BScrollView* scrollView);
|
virtual void TargetedByScrollView(BScrollView* scrollView);
|
||||||
|
|
||||||
@@ -75,6 +78,22 @@ private:
|
|||||||
void _GetNextHexBlock(char* buffer,
|
void _GetNextHexBlock(char* buffer,
|
||||||
int32 bufferSize, const char* address);
|
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:
|
private:
|
||||||
::Team* fTeam;
|
::Team* fTeam;
|
||||||
TeamMemoryBlock* fTargetBlock;
|
TeamMemoryBlock* fTargetBlock;
|
||||||
@@ -87,6 +106,17 @@ private:
|
|||||||
int32 fCurrentEndianMode;
|
int32 fCurrentEndianMode;
|
||||||
int32 fHexMode;
|
int32 fHexMode;
|
||||||
int32 fTextMode;
|
int32 fTextMode;
|
||||||
|
float fHexLeft;
|
||||||
|
float fHexRight;
|
||||||
|
float fTextLeft;
|
||||||
|
float fTextRight;
|
||||||
|
int32 fSelectionBase;
|
||||||
|
int32 fSelectionStart;
|
||||||
|
int32 fSelectionEnd;
|
||||||
|
BMessageRunner* fScrollRunner;
|
||||||
|
|
||||||
|
bool fTrackingMouse;
|
||||||
|
|
||||||
Listener* fListener;
|
Listener* fListener;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user