* Refactored MemoryView to be more flexible ; it can now show a configurable

choice of hexadecimal and/or character displays of the memory data, with
  different digit grouping sizes. Still needs some work but is basically
  functional.



git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42204 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Rene Gollent
2011-06-16 04:21:18 +00:00
parent f7f3828178
commit 2acfac81cd
5 changed files with 259 additions and 40 deletions
@@ -18,16 +18,22 @@
#include "MemoryView.h"
#include "MessageCodes.h"
#include "Team.h"
#include "UserInterface.h"
InspectorWindow::InspectorWindow(UserInterfaceListener* listener)
InspectorWindow::InspectorWindow(::Team* team, UserInterfaceListener* listener)
:
BWindow(BRect(100, 100, 500, 250), "Inspector", B_TITLED_WINDOW,
BWindow(BRect(100, 100, 700, 500), "Inspector", B_TITLED_WINDOW,
B_ASYNCHRONOUS_CONTROLS),
fListener(listener),
fAddressInput(NULL),
fHexMode(NULL),
fTextMode(NULL),
fMemoryView(NULL),
fCurrentBlock(NULL)
fCurrentBlock(NULL),
fCurrentAddress(0LL),
fTeam(team)
{
}
@@ -38,9 +44,9 @@ InspectorWindow::~InspectorWindow()
/* static */ InspectorWindow*
InspectorWindow::Create(UserInterfaceListener* listener)
InspectorWindow::Create(::Team* team, UserInterfaceListener* listener)
{
InspectorWindow* self = new InspectorWindow(listener);
InspectorWindow* self = new InspectorWindow(team, listener);
try {
self->_Init();
@@ -58,17 +64,72 @@ InspectorWindow::_Init()
{
BScrollView* scrollView;
BMenu* hexMenu = new BMenu("Hex Mode");
BMessage* message = new BMessage(MSG_SET_HEX_MODE);
message->AddInt32("mode", HexModeNone);
BMenuItem* item = new BMenuItem("<None>", message, '0');
hexMenu->AddItem(item);
message = new BMessage(*message);
message->ReplaceInt32("mode", HexMode8BitInt);
item = new BMenuItem("8-bit integer", message, '1');
hexMenu->AddItem(item);
message = new BMessage(*message);
message->ReplaceInt32("mode", HexMode16BitInt);
item = new BMenuItem("16-bit integer", message, '2');
hexMenu->AddItem(item);
message = new BMessage(*message);
message->ReplaceInt32("mode", HexMode32BitInt);
item = new BMenuItem("32-bit integer", message, '3');
hexMenu->AddItem(item);
// TODO: enable once problem with 64-bit hex string formatting is found
/*
message = new BMessage(*message);
message->ReplaceInt32("mode", HexMode64BitInt);
item = new BMenuItem("64-bit integer", message, '3');
hexMenu->AddItem(item);
*/
BMenu* textMenu = new BMenu("Text Mode");
message = new BMessage(MSG_SET_TEXT_MODE);
message->AddInt32("mode", TextModeNone);
item = new BMenuItem("<None>", message, 'N');
textMenu->AddItem(item);
message = new BMessage(*message);
message->ReplaceInt32("mode", TextModeASCII);
item = new BMenuItem("ASCII", message, 'A');
textMenu->AddItem(item);
BLayoutBuilder::Group<>(this, B_VERTICAL)
.SetInsets(4.0f, 4.0f, 4.0f, 4.0f)
.Add(fAddressInput = new BTextControl("addrInput",
"Target Address:", "",
new BMessage(MSG_INSPECT_ADDRESS)))
.AddGroup(B_HORIZONTAL, 4.0f)
.Add(fHexMode = new BMenuField("outputStyle", "Hex Mode:",
hexMenu))
.AddGlue()
.Add(fTextMode = new BMenuField("viewMode", "Text Mode:",
textMenu))
.End()
.Add(scrollView = new BScrollView("memory scroll",
NULL, 0, false, true), 3.0f)
.End();
fHexMode->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
fTextMode->SetViewColor(ui_color(B_PANEL_BACKGROUND_COLOR));
scrollView->SetTarget(fMemoryView = MemoryView::Create());
fAddressInput->SetTarget(this);
hexMenu->SetLabelFromMarked(true);
hexMenu->SetTargetForItems(fMemoryView);
textMenu->SetLabelFromMarked(true);
textMenu->SetTargetForItems(fMemoryView);
// default to 8-bit format w/ text display
hexMenu->ItemAt(1)->SetMarked(true);
textMenu->ItemAt(1)->SetMarked(true);
}
@@ -13,19 +13,22 @@
class BButton;
class BMenuField;
class BTextControl;
class MemoryView;
class Team;
class UserInterfaceListener;
class InspectorWindow : public BWindow,
public TeamMemoryBlock::Listener {
public:
InspectorWindow(
InspectorWindow(::Team* team,
UserInterfaceListener* listener);
virtual ~InspectorWindow();
static InspectorWindow* Create(UserInterfaceListener* listener);
static InspectorWindow* Create(::Team* team,
UserInterfaceListener* listener);
// throws
virtual void MessageReceived(BMessage* message);
@@ -39,9 +42,12 @@ private:
private:
UserInterfaceListener* fListener;
BTextControl* fAddressInput;
BMenuField* fHexMode;
BMenuField* fTextMode;
MemoryView* fMemoryView;
TeamMemoryBlock* fCurrentBlock;
target_addr_t fCurrentAddress;
::Team* fTeam;
};
#endif // INSPECTOR_WINDOW_H
@@ -6,6 +6,8 @@
#include "MemoryView.h"
#include <algorithm>
#include <stdio.h>
#include <Messenger.h>
@@ -24,7 +26,13 @@ MemoryView::MemoryView()
:
BView("memoryView", B_WILL_DRAW | B_FRAME_EVENTS | B_SUBPIXEL_PRECISE),
fTargetBlock(NULL),
fTargetAddress(0)
fTargetAddress(0LL),
fCharWidth(0.0),
fLineHeight(0.0),
fTextCharsPerLine(0),
fHexBlocksPerLine(0),
fHexMode(HexMode8BitInt),
fTextMode(TextModeASCII)
{
}
@@ -92,42 +100,77 @@ MemoryView::Draw(BRect rect)
{
BView::Draw(rect);
StrokeLine(BPoint(9 * fCharWidth, rect.top),
BPoint(9 * fCharWidth, rect.bottom));
float divider = 9 * fCharWidth;
StrokeLine(BPoint(divider, rect.top),
BPoint(divider, rect.bottom));
if (fTargetBlock == NULL)
return;
char buffer[16];
uint32 hexBlockSize = 1 << fHexMode;
if (fHexMode != HexModeNone && fTextMode != TextModeNone) {
divider += (fHexBlocksPerLine * (hexBlockSize + 1) + 1) * fCharWidth;
StrokeLine(BPoint(divider, rect.top),
BPoint(divider, rect.bottom));
}
int32 startLine = int32(rect.top / fLineHeight);
char buffer[32];
char textbuffer[512];
int32 startLine = int32(rect.top / fLineHeight) - 1;
if (startLine < 0)
startLine = 0;
int32 endLine = int32(rect.bottom / fLineHeight) + 1;
int32 startByte = fNybblesPerLine / 2 * startLine;
uint16* currentAddress = (uint16*)(fTargetBlock->BaseAddress()
int32 startByte = fHexBlocksPerLine * hexBlockSize * startLine;
const char* currentAddress = (const char*)(fTargetBlock->BaseAddress()
+ startByte);
uint16* maxAddress = (uint16*)(fTargetBlock->BaseAddress()
const char* maxAddress = (const char*)(fTargetBlock->BaseAddress()
+ fTargetBlock->Size());
BPoint drawPoint(1.0, (startLine + 1) * fLineHeight);
int32 currentWordsPerLine = fNybblesPerLine / 4;
int32 currentBlocksPerLine = fHexBlocksPerLine;
int32 currentCharsPerLine = fTextCharsPerLine;
rgb_color addressColor = tint_color(HighColor(), B_LIGHTEN_1_TINT);
rgb_color dataColor = HighColor();
for (int32 i = startLine; i <= endLine && currentAddress < maxAddress;
i++, drawPoint.y += fLineHeight) {
drawPoint.x = 1.0;
snprintf(buffer, sizeof(buffer), "%" B_PRIx32,
(uint32)currentAddress);
SetHighColor(addressColor);
DrawString(buffer, drawPoint);
drawPoint.x += fCharWidth * 10;
SetHighColor(dataColor);
if (currentAddress + currentWordsPerLine > maxAddress)
currentWordsPerLine = (maxAddress - currentAddress) / 2;
if (fHexMode != HexModeNone) {
if (currentAddress + (currentBlocksPerLine * hexBlockSize)
> maxAddress) {
currentCharsPerLine = maxAddress - currentAddress;
currentBlocksPerLine = currentCharsPerLine
/ hexBlockSize;
}
for (int32 j = 0; j < currentWordsPerLine; j++) {
snprintf(buffer, sizeof(buffer), "%04" B_PRIx16,
currentAddress[j]);
DrawString(buffer, drawPoint);
drawPoint.x += fCharWidth * 5;
for (int32 j = 0; j < currentBlocksPerLine; j++) {
_GetNextHexBlock(buffer,
std::min(hexBlockSize + 1, sizeof(buffer)),
currentAddress + (j * hexBlockSize / 2));
DrawString(buffer, drawPoint);
drawPoint.x += fCharWidth * (hexBlockSize + 1);
}
}
currentAddress += currentWordsPerLine;
if (fTextMode != TextModeNone) {
drawPoint.x += fCharWidth;
for (int32 j = 0; j < currentCharsPerLine; j++) {
// filter non-printable characters
textbuffer[j] = currentAddress[j] > 32 ? currentAddress[j]
: '.';
}
textbuffer[fTextCharsPerLine] = '\0';
DrawString(textbuffer, drawPoint);
}
if (currentBlocksPerLine > 0)
currentAddress += currentBlocksPerLine * hexBlockSize / 2;
else
currentAddress += fTextCharsPerLine;
}
}
@@ -151,6 +194,26 @@ MemoryView::MessageReceived(BMessage* message)
Invalidate();
break;
}
case MSG_SET_HEX_MODE:
{
int32 mode;
if (message->FindInt32("mode", &mode) == B_OK) {
fHexMode = mode;
_RecalcScrollBars();
Invalidate();
}
break;
}
case MSG_SET_TEXT_MODE:
{
int32 mode;
if (message->FindInt32("mode", &mode) == B_OK) {
fTextMode = mode;
_RecalcScrollBars();
Invalidate();
}
break;
}
default:
{
BView::MessageReceived(message);
@@ -174,19 +237,83 @@ MemoryView::_RecalcScrollBars()
BScrollBar *scrollBar = ScrollBar(B_VERTICAL);
if (fTargetBlock != NULL) {
BRect bounds = Bounds();
fNybblesPerLine = int32(bounds.Width() / fCharWidth);
// we allocate 8 characters for the starting address of the current
// line plus some spacing to separate that from the data
fNybblesPerLine -= 10;
// also allocate a space between each 16-bit grouping
fNybblesPerLine -= (fNybblesPerLine / 4) - 1;
fNybblesPerLine &= ~3;
int32 lineCount
= (int32)ceil(2 * fTargetBlock->Size() / fNybblesPerLine);
float totalHeight = lineCount * fLineHeight;
max = totalHeight - bounds.Height();
scrollBar->SetProportion(bounds.Height() / totalHeight);
scrollBar->SetSteps(fLineHeight, bounds.Height());
// the left portion of the view is off limits since it
// houses the address offset of the current line
float baseWidth = bounds.Width() - (10.0 * fCharWidth);
float hexWidth = 0.0;
float textWidth = 0.0;
int32 hexDigits = 1 << fHexMode;
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;
int32 nybblesPerLine = int32(hexWidth / fCharWidth);
fHexBlocksPerLine = 0;
fTextCharsPerLine = 0;
if (fHexMode != HexModeNone) {
fHexBlocksPerLine = nybblesPerLine / sizeFactor;
fHexBlocksPerLine &= ~1;
if (fTextMode != TextModeNone)
fTextCharsPerLine = fHexBlocksPerLine * (hexDigits / 2);
} else if (fTextMode != TextModeNone)
fTextCharsPerLine = int32(textWidth / fCharWidth);
int32 lineCount = 0;
float totalHeight = 0.0;
if (fHexBlocksPerLine > 0) {
lineCount = fTargetBlock->Size() / (fHexBlocksPerLine
* hexDigits);
} else if (fTextCharsPerLine > 0)
lineCount = fTargetBlock->Size() / fTextCharsPerLine;
totalHeight = lineCount * fLineHeight;
if (totalHeight > 0.0) {
max = totalHeight - bounds.Height();
scrollBar->SetProportion(bounds.Height() / totalHeight);
scrollBar->SetSteps(fLineHeight, bounds.Height());
}
}
scrollBar->SetRange(0.0, max);
}
void
MemoryView::_GetNextHexBlock(char* buffer, int32 bufferSize,
const char* address)
{
switch(fHexMode) {
case HexMode8BitInt:
{
snprintf(buffer, bufferSize, "%02" B_PRIx8, *address);
break;
}
case HexMode16BitInt:
{
snprintf(buffer, bufferSize, "%04" B_PRIx16,
*((const uint16*)address));
break;
}
case HexMode32BitInt:
{
snprintf(buffer, bufferSize, "%08" B_PRIx32,
*((const uint32*)address));
break;
}
case HexMode64BitInt:
{
snprintf(buffer, bufferSize, "%0*" B_PRIx64,
16, *((const uint64*)address));
break;
}
}
}
@@ -12,6 +12,26 @@
#include "Types.h"
enum {
MSG_SET_HEX_MODE = 'sofm',
MSG_SET_TEXT_MODE = 'some'
};
enum {
HexModeNone = 0,
HexMode8BitInt,
HexMode16BitInt,
HexMode32BitInt,
HexMode64BitInt
// TODO: floating point representation?
};
enum {
TextModeNone = 0,
TextModeASCII
};
class TeamMemoryBlock;
@@ -39,13 +59,18 @@ public:
private:
void _Init();
void _RecalcScrollBars();
void _GetNextHexBlock(char* buffer,
int32 bufferSize, const char* address);
private:
TeamMemoryBlock* fTargetBlock;
target_addr_t fTargetAddress;
float fCharWidth;
float fLineHeight;
int32 fNybblesPerLine;
int32 fTextCharsPerLine;
int32 fHexBlocksPerLine;
int32 fHexMode;
int32 fTextMode;
};
#endif // MEMORY_VIEW_H
@@ -212,7 +212,7 @@ TeamWindow::MessageReceived(BMessage* message)
}
try {
fInspectorWindow = InspectorWindow::Create(fListener);
fInspectorWindow = InspectorWindow::Create(fTeam, fListener);
if (fInspectorWindow != NULL)
fInspectorWindow->Show();
} catch (...) {