2 * Copyright 2011-2015, Rene Gollent, rene@gollent.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
7 #include "MemoryView.h"
14 #include <ByteOrder.h>
15 #include <Clipboard.h>
18 #include <MessageRunner.h>
19 #include <Messenger.h>
20 #include <PopUpMenu.h>
22 #include <ScrollView.h>
25 #include "Architecture.h"
26 #include "AutoDeleter.h"
27 #include "MessageCodes.h"
29 #include "TeamMemoryBlock.h"
33 MSG_TARGET_ADDRESS_CHANGED
= 'mtac',
34 MSG_VIEW_AUTOSCROLL
= 'mvas'
37 static const bigtime_t kScrollTimer
= 10000LL;
40 MemoryView::MemoryView(::Team
* team
, Listener
* listener
)
42 BView("memoryView", B_WILL_DRAW
| B_FRAME_EVENTS
| B_NAVIGABLE
43 | B_SUBPIXEL_PRECISE
),
50 fEditLowNybble(false),
55 fHexMode(HexMode8BitInt
),
56 fTextMode(TextModeASCII
),
61 fTrackingMouse(false),
64 Architecture
* architecture
= team
->GetArchitecture();
65 fTargetAddressSize
= architecture
->AddressSize() * 2;
66 fCurrentEndianMode
= architecture
->IsBigEndian()
67 ? EndianModeBigEndian
: EndianModeLittleEndian
;
72 MemoryView::~MemoryView()
74 if (fTargetBlock
!= NULL
)
75 fTargetBlock
->ReleaseReference();
77 delete[] fEditableData
;
81 /*static */ MemoryView
*
82 MemoryView::Create(::Team
* team
, Listener
* listener
)
84 MemoryView
* self
= new MemoryView(team
, listener
);
98 MemoryView::SetTargetAddress(TeamMemoryBlock
* block
, target_addr_t address
)
100 fTargetAddress
= address
;
101 if (block
!= fTargetBlock
) {
102 if (fTargetBlock
!= NULL
)
103 fTargetBlock
->ReleaseReference();
105 fTargetBlock
= block
;
107 fTargetBlock
->AcquireReference();
111 BMessenger(this).SendMessage(MSG_TARGET_ADDRESS_CHANGED
);
116 MemoryView::UnsetListener()
123 MemoryView::SetEditMode(bool enabled
)
125 if (fTargetBlock
== NULL
)
127 else if (fEditMode
== enabled
)
131 status_t error
= _SetupEditableData();
135 delete[] fEditableData
;
136 fEditableData
= NULL
;
137 fEditedOffsets
.clear();
138 fEditLowNybble
= false;
149 MemoryView::AttachedToWindow()
151 BView::AttachedToWindow();
152 SetViewUIColor(B_DOCUMENT_BACKGROUND_COLOR
);
153 SetFont(be_fixed_font
);
154 fCharWidth
= be_fixed_font
->StringWidth("a");
155 font_height fontHeight
;
156 be_fixed_font
->GetHeight(&fontHeight
);
157 fLineHeight
= ceilf(fontHeight
.ascent
+ fontHeight
.descent
158 + fontHeight
.leading
);
163 MemoryView::Draw(BRect rect
)
167 float divider
= (fTargetAddressSize
+ 1) * fCharWidth
;
168 StrokeLine(BPoint(divider
, rect
.top
),
169 BPoint(divider
, rect
.bottom
));
171 if (fTargetBlock
== NULL
)
174 uint32 hexBlockSize
= _GetHexDigitsPerBlock() + 1;
175 uint32 blockByteSize
= hexBlockSize
/ 2;
176 if (fHexMode
!= HexModeNone
&& fTextMode
!= TextModeNone
) {
177 divider
+= (fHexBlocksPerLine
* hexBlockSize
+ 1) * fCharWidth
;
178 StrokeLine(BPoint(divider
, rect
.top
),
179 BPoint(divider
, rect
.bottom
));
183 char textbuffer
[512];
185 const char* dataSource
= (const char*)(fEditMode
? fEditableData
186 : fTargetBlock
->Data());
188 int32 startLine
= int32(rect
.top
/ fLineHeight
);
189 const char* currentAddress
= dataSource
+ fHexBlocksPerLine
190 * blockByteSize
* startLine
;
191 const char* maxAddress
= dataSource
+ fTargetBlock
->Size();
192 const char* targetAddress
= dataSource
+ fTargetAddress
193 - fTargetBlock
->BaseAddress();
194 BPoint
drawPoint(1.0, (startLine
+ 1) * fLineHeight
);
195 int32 currentBlocksPerLine
= fHexBlocksPerLine
;
196 int32 currentCharsPerLine
= fTextCharsPerLine
;
197 rgb_color addressColor
= tint_color(HighColor(), B_LIGHTEN_1_TINT
);
198 rgb_color dataColor
= HighColor();
201 target_addr_t lineAddress
= fTargetBlock
->BaseAddress() + startLine
202 * currentCharsPerLine
;
203 bool highlightBlock
= false;
204 rgb_color highlightColor
;
205 for (; currentAddress
< maxAddress
&& drawPoint
.y
< rect
.bottom
206 + fLineHeight
; drawPoint
.y
+= fLineHeight
) {
208 snprintf(buffer
, sizeof(buffer
), "%0*" B_PRIx64
,
209 (int)fTargetAddressSize
, lineAddress
);
211 SetHighColor(tint_color(HighColor(), B_LIGHTEN_1_TINT
));
212 DrawString(buffer
, drawPoint
);
213 drawPoint
.x
+= fCharWidth
* (fTargetAddressSize
+ 2);
215 if (fHexMode
!= HexModeNone
) {
216 if (currentAddress
+ (currentBlocksPerLine
* blockByteSize
)
218 currentCharsPerLine
= maxAddress
- currentAddress
;
219 currentBlocksPerLine
= currentCharsPerLine
223 for (int32 j
= 0; j
< currentBlocksPerLine
; j
++) {
224 const char* blockAddress
= currentAddress
+ (j
226 _GetNextHexBlock(buffer
, sizeof(buffer
), blockAddress
);
228 highlightBlock
= false;
231 int32 offset
= blockAddress
- dataSource
;
232 for (uint32 i
= 0; i
< blockByteSize
; i
++) {
233 if (fEditedOffsets
.count(offset
+ i
) != 0) {
234 highlightBlock
= true;
235 highlightColor
.set_to(0, 216, 0);
240 } else if (targetAddress
>= blockAddress
&& targetAddress
<
241 blockAddress
+ blockByteSize
) {
242 highlightBlock
= true;
243 highlightColor
.set_to(216, 0, 0);
246 if (highlightBlock
) {
248 SetHighColor(highlightColor
);
251 DrawString(buffer
, drawPoint
);
256 drawPoint
.x
+= fCharWidth
* hexBlockSize
;
259 if (currentBlocksPerLine
< fHexBlocksPerLine
)
260 drawPoint
.x
+= fCharWidth
* hexBlockSize
261 * (fHexBlocksPerLine
- currentBlocksPerLine
);
264 if (fTextMode
!= TextModeNone
) {
265 drawPoint
.x
+= fCharWidth
;
266 for (int32 j
= 0; j
< currentCharsPerLine
; j
++) {
267 // filter non-printable characters
268 textbuffer
[j
] = currentAddress
[j
] > 32 ? currentAddress
[j
]
271 textbuffer
[fTextCharsPerLine
] = '\0';
272 DrawString(textbuffer
, drawPoint
);
273 if (targetAddress
>= currentAddress
&& targetAddress
274 < currentAddress
+ currentCharsPerLine
) {
276 SetHighColor(B_TRANSPARENT_COLOR
);
277 SetDrawingMode(B_OP_INVERT
);
278 uint32 blockAddress
= uint32(targetAddress
- currentAddress
);
279 if (fHexMode
!= HexModeNone
)
280 blockAddress
&= ~(blockByteSize
- 1);
281 float startX
= drawPoint
.x
+ fCharWidth
* blockAddress
;
283 if (fHexMode
!= HexModeNone
)
284 endX
+= fCharWidth
* ((hexBlockSize
- 1) / 2);
287 FillRect(BRect(startX
, drawPoint
.y
- fh
.ascent
, endX
,
288 drawPoint
.y
+ fh
.descent
));
292 if (currentBlocksPerLine
> 0) {
293 currentAddress
+= currentBlocksPerLine
* blockByteSize
;
294 lineAddress
+= currentBlocksPerLine
* blockByteSize
;
296 currentAddress
+= fTextCharsPerLine
;
297 lineAddress
+= fTextCharsPerLine
;
301 if (fSelectionStart
!= fSelectionEnd
) {
303 BRegion selectionRegion
;
304 _GetSelectionRegion(selectionRegion
);
305 SetDrawingMode(B_OP_INVERT
);
306 FillRegion(&selectionRegion
, B_SOLID_HIGH
);
313 _GetEditCaretRect(caretRect
);
314 SetDrawingMode(B_OP_INVERT
);
315 FillRect(caretRect
, B_SOLID_HIGH
);
323 MemoryView::FrameResized(float width
, float height
)
325 BView::FrameResized(width
, height
);
332 MemoryView::KeyDown(const char* bytes
, int32 numBytes
)
335 if (fTargetBlock
!= NULL
) {
336 target_addr_t newAddress
= fTargetAddress
;
337 target_addr_t maxAddress
= fTargetBlock
->BaseAddress()
338 + fTargetBlock
->Size() - 1;
340 if (fHexMode
!= HexModeNone
)
341 blockSize
= 1 << (fHexMode
- 1);
342 int32 lineCount
= int32(Bounds().Height() / fLineHeight
);
347 newAddress
-= blockSize
* fHexBlocksPerLine
;
352 newAddress
+= blockSize
* fHexBlocksPerLine
;
360 fEditLowNybble
= !fEditLowNybble
;
361 if (newAddress
== fTargetAddress
)
364 newAddress
-= blockSize
;
372 fEditLowNybble
= !fEditLowNybble
;
373 if (newAddress
== fTargetAddress
)
376 newAddress
+= blockSize
;
381 newAddress
-= (blockSize
* fHexBlocksPerLine
) * lineCount
;
386 newAddress
+= (blockSize
* fHexBlocksPerLine
) * lineCount
;
391 newAddress
= fTargetBlock
->BaseAddress();
392 fEditLowNybble
= false;
397 newAddress
= maxAddress
;
398 fEditLowNybble
= true;
403 if (fEditMode
&& isxdigit(bytes
[0]))
406 if (isdigit(bytes
[0]))
407 value
= bytes
[0] - '0';
409 value
= (int)strtol(bytes
, NULL
, 16);
411 int32 byteOffset
= fTargetAddress
412 - fTargetBlock
->BaseAddress();
415 value
= (fEditableData
[byteOffset
] & 0xf0) | value
;
417 value
= (fEditableData
[byteOffset
] & 0x0f)
421 fEditableData
[byteOffset
] = value
;
423 if (fEditableData
[byteOffset
]
424 != fTargetBlock
->Data()[byteOffset
]) {
425 fEditedOffsets
.insert(byteOffset
);
427 fEditedOffsets
.erase(byteOffset
);
429 if (fEditLowNybble
) {
430 if (newAddress
< maxAddress
) {
432 fEditLowNybble
= false;
435 fEditLowNybble
= true;
446 if (newAddress
< fTargetBlock
->BaseAddress())
447 newAddress
= fTargetAddress
;
448 else if (newAddress
> maxAddress
)
449 newAddress
= maxAddress
;
451 if (newAddress
!= fTargetAddress
) {
452 fTargetAddress
= newAddress
;
453 BMessenger(this).SendMessage(MSG_TARGET_ADDRESS_CHANGED
);
460 BView::KeyDown(bytes
, numBytes
);
465 MemoryView::MakeFocus(bool isFocused
)
467 BScrollView
* parent
= dynamic_cast<BScrollView
*>(Parent());
469 parent
->SetBorderHighlighted(isFocused
);
471 BView::MakeFocus(isFocused
);
476 MemoryView::MessageReceived(BMessage
* message
)
478 switch(message
->what
) {
481 _CopySelectionToClipboard();
484 case MSG_TARGET_ADDRESS_CHANGED
:
489 if (fListener
!= NULL
)
490 fListener
->TargetAddressChanged(fTargetAddress
);
493 case MSG_SET_HEX_MODE
:
495 // while editing, hex view changes are disallowed.
500 if (message
->FindInt32("mode", &mode
) == B_OK
) {
501 if (fHexMode
== mode
)
508 if (fListener
!= NULL
)
509 fListener
->HexModeChanged(mode
);
513 case MSG_SET_ENDIAN_MODE
:
516 if (message
->FindInt32("mode", &mode
) == B_OK
) {
517 if (fCurrentEndianMode
== mode
)
520 fCurrentEndianMode
= mode
;
523 if (fListener
!= NULL
)
524 fListener
->EndianModeChanged(mode
);
528 case MSG_SET_TEXT_MODE
:
531 if (message
->FindInt32("mode", &mode
) == B_OK
) {
532 if (fTextMode
== mode
)
539 if (fListener
!= NULL
)
540 fListener
->TextModeChanged(mode
);
544 case MSG_VIEW_AUTOSCROLL
:
551 BView::MessageReceived(message
);
559 MemoryView::MouseDown(BPoint point
)
564 if (fTargetBlock
== NULL
)
568 if (Looper()->CurrentMessage()->FindInt32("buttons", &buttons
) != B_OK
)
569 buttons
= B_PRIMARY_MOUSE_BUTTON
;
571 if (buttons
== B_SECONDARY_MOUSE_BUTTON
) {
572 _HandleContextMenu(point
);
576 int32 offset
= _GetOffsetAt(point
);
577 if (offset
< fSelectionStart
|| offset
> fSelectionEnd
) {
578 BRegion oldSelectionRegion
;
579 _GetSelectionRegion(oldSelectionRegion
);
580 fSelectionBase
= offset
;
581 fSelectionStart
= fSelectionBase
;
582 fSelectionEnd
= fSelectionBase
;
583 Invalidate(oldSelectionRegion
.Frame());
586 SetMouseEventMask(B_POINTER_EVENTS
, B_NO_POINTER_HISTORY
);
587 fTrackingMouse
= true;
592 MemoryView::MouseMoved(BPoint point
, uint32 transit
, const BMessage
* message
)
597 BRegion oldSelectionRegion
;
598 _GetSelectionRegion(oldSelectionRegion
);
599 int32 offset
= _GetOffsetAt(point
);
600 if (offset
< fSelectionBase
) {
601 fSelectionStart
= offset
;
602 fSelectionEnd
= fSelectionBase
;
604 fSelectionStart
= fSelectionBase
;
605 fSelectionEnd
= offset
;
609 _GetSelectionRegion(region
);
610 region
.Include(&oldSelectionRegion
);
611 Invalidate(region
.Frame());
615 fScrollRunner
= new BMessageRunner(BMessenger(this),
616 new BMessage(MSG_VIEW_AUTOSCROLL
), kScrollTimer
);
620 delete fScrollRunner
;
621 fScrollRunner
= NULL
;
631 MemoryView::MouseUp(BPoint point
)
633 fTrackingMouse
= false;
634 delete fScrollRunner
;
635 fScrollRunner
= NULL
;
640 MemoryView::ScrollToSelection()
642 if (fTargetBlock
!= NULL
) {
643 target_addr_t offset
= fTargetAddress
- fTargetBlock
->BaseAddress();
644 int32 lineNumber
= 0;
645 if (fHexBlocksPerLine
> 0) {
646 lineNumber
= offset
/ (fHexBlocksPerLine
647 * (_GetHexDigitsPerBlock() / 2));
648 } else if (fTextCharsPerLine
> 0)
649 lineNumber
= offset
/ fTextCharsPerLine
;
651 float y
= lineNumber
* fLineHeight
;
652 if (y
< Bounds().top
)
654 else if (y
+ fLineHeight
> Bounds().bottom
)
655 ScrollTo(0.0, y
+ fLineHeight
- Bounds().Height());
661 MemoryView::TargetedByScrollView(BScrollView
* scrollView
)
663 BView::TargetedByScrollView(scrollView
);
664 scrollView
->ScrollBar(B_VERTICAL
)->SetRange(0.0, 0.0);
669 MemoryView::MinSize()
671 return BSize(0.0, 0.0);
676 MemoryView::PreferredSize()
683 MemoryView::MaxSize()
685 return BSize(B_SIZE_UNLIMITED
, B_SIZE_UNLIMITED
);
692 SetViewUIColor(B_PANEL_BACKGROUND_COLOR
);
697 MemoryView::_RecalcScrollBars()
700 BScrollBar
*scrollBar
= ScrollBar(B_VERTICAL
);
701 if (fTargetBlock
!= NULL
) {
702 int32 hexDigits
= _GetHexDigitsPerBlock();
703 int32 sizeFactor
= 1 + hexDigits
;
706 float hexWidth
= fHexRight
- fHexLeft
;
707 int32 nybblesPerLine
= int32(hexWidth
/ fCharWidth
);
708 fHexBlocksPerLine
= 0;
709 fTextCharsPerLine
= 0;
710 if (fHexMode
!= HexModeNone
) {
711 fHexBlocksPerLine
= nybblesPerLine
/ sizeFactor
;
712 fHexBlocksPerLine
&= ~1;
713 fHexRight
= fHexLeft
+ (fHexBlocksPerLine
* sizeFactor
715 if (fTextMode
!= TextModeNone
)
716 fTextCharsPerLine
= fHexBlocksPerLine
* hexDigits
/ 2;
717 } else if (fTextMode
!= TextModeNone
)
718 fTextCharsPerLine
= int32((fTextRight
- fTextLeft
) / fCharWidth
);
720 float totalHeight
= 0.0;
721 if (fHexBlocksPerLine
> 0) {
722 lineCount
= fTargetBlock
->Size() / (fHexBlocksPerLine
724 } else if (fTextCharsPerLine
> 0)
725 lineCount
= fTargetBlock
->Size() / fTextCharsPerLine
;
727 totalHeight
= lineCount
* fLineHeight
;
728 if (totalHeight
> 0.0) {
729 BRect bounds
= Bounds();
730 max
= totalHeight
- bounds
.Height();
731 scrollBar
->SetProportion(bounds
.Height() / totalHeight
);
732 scrollBar
->SetSteps(fLineHeight
, bounds
.Height());
735 scrollBar
->SetRange(0.0, max
);
739 MemoryView::_GetNextHexBlock(char* buffer
, int32 bufferSize
,
740 const char* address
) const
745 snprintf(buffer
, bufferSize
, "%02" B_PRIx8
,
746 *((const uint8
*)address
));
749 case HexMode16BitInt
:
751 uint16 data
= *((const uint16
*)address
);
752 switch(fCurrentEndianMode
)
754 case EndianModeBigEndian
:
756 data
= B_HOST_TO_BENDIAN_INT16(data
);
760 case EndianModeLittleEndian
:
762 data
= B_HOST_TO_LENDIAN_INT16(data
);
766 snprintf(buffer
, bufferSize
, "%04" B_PRIx16
,
770 case HexMode32BitInt
:
772 uint32 data
= *((const uint32
*)address
);
773 switch(fCurrentEndianMode
)
775 case EndianModeBigEndian
:
777 data
= B_HOST_TO_BENDIAN_INT32(data
);
781 case EndianModeLittleEndian
:
783 data
= B_HOST_TO_LENDIAN_INT32(data
);
787 snprintf(buffer
, bufferSize
, "%08" B_PRIx32
,
791 case HexMode64BitInt
:
793 uint64 data
= *((const uint64
*)address
);
794 switch(fCurrentEndianMode
)
796 case EndianModeBigEndian
:
798 data
= B_HOST_TO_BENDIAN_INT64(data
);
802 case EndianModeLittleEndian
:
804 data
= B_HOST_TO_LENDIAN_INT64(data
);
808 snprintf(buffer
, bufferSize
, "%0*" B_PRIx64
,
817 MemoryView::_GetOffsetAt(BPoint point
) const
819 if (fTargetBlock
== NULL
)
822 // TODO: support selection in the text region as well
823 if (fHexMode
== HexModeNone
)
826 int32 lineNumber
= int32(point
.y
/ fLineHeight
);
827 int32 charsPerBlock
= _GetHexDigitsPerBlock() / 2;
828 int32 totalHexBlocks
= fTargetBlock
->Size() / charsPerBlock
;
829 int32 lineCount
= totalHexBlocks
/ fHexBlocksPerLine
;
831 if (lineNumber
>= lineCount
)
837 else if (point
.x
> fHexRight
)
840 float blockWidth
= (charsPerBlock
* 2 + 1) * fCharWidth
;
841 int32 containingBlock
= int32(floor(point
.x
/ blockWidth
));
843 return fHexBlocksPerLine
* charsPerBlock
* lineNumber
844 + containingBlock
* charsPerBlock
;
849 MemoryView::_GetPointForOffset(int32 offset
) const
852 if (fHexMode
== HexModeNone
)
855 int32 bytesPerLine
= fHexBlocksPerLine
* _GetHexDigitsPerBlock() / 2;
856 int32 line
= offset
/ bytesPerLine
;
857 int32 lineOffset
= offset
% bytesPerLine
;
859 point
.x
= fHexLeft
+ (lineOffset
* 2 * fCharWidth
)
860 + (lineOffset
* 2 * fCharWidth
/ _GetHexDigitsPerBlock());
861 point
.y
= line
* fLineHeight
;
868 MemoryView::_RecalcBounds()
875 // the left bound is determined by the space taken up by the actual
876 // displayed addresses.
877 float left
= _GetAddressDisplayWidth();
878 float width
= Bounds().Width() - left
;
880 if (fHexMode
!= HexModeNone
) {
881 int32 hexDigits
= _GetHexDigitsPerBlock();
882 int32 sizeFactor
= 1 + hexDigits
;
883 if (fTextMode
!= TextModeNone
) {
884 float hexProportion
= sizeFactor
/ (float)(sizeFactor
886 float hexWidth
= width
* hexProportion
;
887 fTextLeft
= left
+ hexWidth
;
889 // when sharing the display between hex and text,
890 // we allocate a 2 character space to separate the views
891 hexWidth
-= 2 * fCharWidth
;
892 fHexRight
= left
+ hexWidth
;
895 fHexRight
= left
+ width
;
897 } else if (fTextMode
!= TextModeNone
) {
899 fTextRight
= left
+ width
;
905 MemoryView::_GetAddressDisplayWidth() const
907 return (fTargetAddressSize
+ 2) * fCharWidth
;
912 MemoryView::_GetEditCaretRect(BRect
& rect
) const
917 int32 byteOffset
= fTargetAddress
- fTargetBlock
->BaseAddress();
918 BPoint point
= _GetPointForOffset(byteOffset
);
920 point
.x
+= fCharWidth
;
923 rect
.right
= point
.x
+ fCharWidth
;
925 rect
.bottom
= point
.y
+ fLineHeight
;
930 MemoryView::_GetSelectionRegion(BRegion
& region
) const
932 if (fHexMode
== HexModeNone
|| fTargetBlock
== NULL
)
936 BPoint startPoint
= _GetPointForOffset(fSelectionStart
);
937 BPoint endPoint
= _GetPointForOffset(fSelectionEnd
);
940 if (startPoint
.y
== endPoint
.y
) {
942 rect
.left
= startPoint
.x
;
943 rect
.top
= startPoint
.y
;
944 rect
.right
= endPoint
.x
;
945 rect
.bottom
= endPoint
.y
+ fLineHeight
;
946 region
.Include(rect
);
948 float currentLine
= startPoint
.y
;
951 rect
.left
= startPoint
.x
;
952 rect
.top
= startPoint
.y
;
953 rect
.right
= fHexRight
;
954 rect
.bottom
= startPoint
.y
+ fLineHeight
;
955 region
.Include(rect
);
956 currentLine
+= fLineHeight
;
959 if (currentLine
< endPoint
.y
) {
960 rect
.left
= fHexLeft
;
961 rect
.top
= currentLine
;
962 rect
.right
= fHexRight
;
963 rect
.bottom
= endPoint
.y
;
964 region
.Include(rect
);
967 rect
.left
= fHexLeft
;
968 rect
.top
= endPoint
.y
;
969 rect
.right
= endPoint
.x
;
970 rect
.bottom
= endPoint
.y
+ fLineHeight
;
971 region
.Include(rect
);
977 MemoryView::_GetSelectedText(BString
& text
) const
979 if (fSelectionStart
== fSelectionEnd
)
983 const uint8
* dataSource
= fEditMode
? fEditableData
: fTargetBlock
->Data();
985 const char* data
= (const char *)dataSource
+ fSelectionStart
;
986 int16 blockSize
= _GetHexDigitsPerBlock() / 2;
987 int32 count
= (fSelectionEnd
- fSelectionStart
)
991 for (int32 i
= 0; i
< count
; i
++) {
992 _GetNextHexBlock(buffer
, sizeof(buffer
), data
);
1002 MemoryView::_CopySelectionToClipboard()
1005 _GetSelectedText(text
);
1007 if (text
.Length() > 0) {
1008 be_clipboard
->Lock();
1009 be_clipboard
->Data()->RemoveData("text/plain");
1010 be_clipboard
->Data()->AddData ("text/plain",
1011 B_MIME_TYPE
, text
.String(), text
.Length());
1012 be_clipboard
->Commit();
1013 be_clipboard
->Unlock();
1019 MemoryView::_HandleAutoScroll()
1023 GetMouse(&point
, &buttons
);
1024 float difference
= 0.0;
1026 BRect visibleRect
= Bounds();
1027 if (point
.y
< visibleRect
.top
)
1028 difference
= point
.y
- visibleRect
.top
;
1029 else if (point
.y
> visibleRect
.bottom
)
1030 difference
= point
.y
- visibleRect
.bottom
;
1031 if (difference
!= 0.0) {
1032 factor
= (int)(ceilf(difference
/ fLineHeight
));
1033 _ScrollByLines(factor
);
1036 MouseMoved(point
, B_OUTSIDE_VIEW
, NULL
);
1041 MemoryView::_ScrollByLines(int32 lineCount
)
1043 BScrollBar
* vertical
= ScrollBar(B_VERTICAL
);
1044 if (vertical
== NULL
)
1047 float value
= vertical
->Value();
1048 vertical
->SetValue(value
+ fLineHeight
* lineCount
);
1053 MemoryView::_HandleContextMenu(BPoint point
)
1055 int32 offset
= _GetOffsetAt(point
);
1056 if (offset
< fSelectionStart
|| offset
> fSelectionEnd
)
1059 BPopUpMenu
* menu
= new(std::nothrow
) BPopUpMenu("Options");
1063 ObjectDeleter
<BPopUpMenu
> menuDeleter(menu
);
1064 ObjectDeleter
<BMenuItem
> itemDeleter
;
1065 ObjectDeleter
<BMessage
> messageDeleter
;
1066 BMessage
* message
= NULL
;
1067 BMenuItem
* item
= NULL
;
1068 if (fSelectionEnd
- fSelectionStart
== fTargetAddressSize
/ 2) {
1069 BMessage
* message
= new(std::nothrow
) BMessage(MSG_INSPECT_ADDRESS
);
1070 if (message
== NULL
)
1073 target_addr_t address
;
1074 if (fTargetAddressSize
== 8)
1075 address
= *((uint32
*)(fTargetBlock
->Data() + fSelectionStart
));
1077 address
= *((uint64
*)(fTargetBlock
->Data() + fSelectionStart
));
1079 if (fCurrentEndianMode
== EndianModeBigEndian
)
1080 address
= B_HOST_TO_BENDIAN_INT64(address
);
1082 address
= B_HOST_TO_LENDIAN_INT64(address
);
1084 messageDeleter
.SetTo(message
);
1085 message
->AddUInt64("address", address
);
1086 BMenuItem
* item
= new(std::nothrow
) BMenuItem("Inspect", message
);
1090 messageDeleter
.Detach();
1091 itemDeleter
.SetTo(item
);
1092 if (!menu
->AddItem(item
))
1095 item
->SetTarget(Looper());
1096 itemDeleter
.Detach();
1099 message
= new(std::nothrow
) BMessage(B_COPY
);
1100 if (message
== NULL
)
1103 messageDeleter
.SetTo(message
);
1104 item
= new(std::nothrow
) BMenuItem("Copy", message
);
1108 messageDeleter
.Detach();
1109 itemDeleter
.SetTo(item
);
1110 if (!menu
->AddItem(item
))
1113 item
->SetTarget(this);
1114 itemDeleter
.Detach();
1115 menuDeleter
.Detach();
1117 BPoint
screenWhere(point
);
1118 ConvertToScreen(&screenWhere
);
1119 BRect
mouseRect(screenWhere
, screenWhere
);
1120 mouseRect
.InsetBy(-4.0, -4.0);
1121 menu
->Go(screenWhere
, true, false, mouseRect
, true);
1126 MemoryView::_SetupEditableData()
1128 fEditableData
= new(std::nothrow
) uint8
[fTargetBlock
->Size()];
1129 if (fEditableData
== NULL
)
1132 memcpy(fEditableData
, fTargetBlock
->Data(), fTargetBlock
->Size());
1134 if (fHexMode
!= HexMode8BitInt
) {
1135 fHexMode
= HexMode8BitInt
;
1136 if (fListener
!= NULL
)
1137 fListener
->HexModeChanged(fHexMode
);
1139 _RecalcScrollBars();
1146 //#pragma mark - Listener
1149 MemoryView::Listener::~Listener()