Implemented the selection code.
git-svn-id: file:///srv/svn/repos/haiku/trunk/current@6571 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -8,26 +8,35 @@
|
||||
#include "DataEditor.h"
|
||||
|
||||
#include <Messenger.h>
|
||||
#include <Looper.h>
|
||||
|
||||
|
||||
static const uint32 kBlockSize = 16;
|
||||
static const uint32 kHorizontalSpace = 8;
|
||||
static const uint32 kVerticalSpace = 4;
|
||||
|
||||
static const uint32 kBlockSpace = 3;
|
||||
static const uint32 kHexByteWidth = 3;
|
||||
// these are determined by the implementation of DataView::ConvertLine()
|
||||
|
||||
|
||||
DataView::DataView(BRect rect, DataEditor &editor)
|
||||
: BView(rect, "dataView", B_FOLLOW_ALL, B_WILL_DRAW | B_NAVIGABLE | B_FRAME_EVENTS),
|
||||
fEditor(editor)
|
||||
fEditor(editor),
|
||||
fFocus(kHexFocus),
|
||||
fIsActive(true)
|
||||
{
|
||||
fPositionLength = 4;
|
||||
fStart = fEnd = 0;
|
||||
fMouseSelectionStart = -1;
|
||||
|
||||
fDataSize = fEditor.ViewSize();
|
||||
fData = (uint8 *)malloc(fDataSize);
|
||||
|
||||
SetFontSize(12.0);
|
||||
// also sets the fixed font
|
||||
|
||||
UpdateFromEditor();
|
||||
|
||||
SetFont(be_fixed_font);
|
||||
}
|
||||
|
||||
|
||||
@@ -141,10 +150,385 @@ DataView::Draw(BRect updateRect)
|
||||
location.y += fFontHeight;
|
||||
}
|
||||
// ToDo: clear unused space!
|
||||
|
||||
DrawSelection();
|
||||
}
|
||||
|
||||
|
||||
int32
|
||||
DataView::PositionAt(view_focus focus, BPoint point, view_focus *_newFocus)
|
||||
{
|
||||
float left = fCharWidth * (fPositionLength + kBlockSpace) + kHorizontalSpace;
|
||||
float hexWidth = fCharWidth * kBlockSize * kHexByteWidth;
|
||||
float width = fCharWidth;
|
||||
|
||||
if (focus == kNoFocus) {
|
||||
// find in which part the point is in
|
||||
if (point.x < left - width / 2)
|
||||
return -1;
|
||||
|
||||
if (point.x > left + hexWidth)
|
||||
focus = kAsciiFocus;
|
||||
else
|
||||
focus = kHexFocus;
|
||||
|
||||
if (_newFocus)
|
||||
*_newFocus = focus;
|
||||
}
|
||||
if (focus == kHexFocus) {
|
||||
left -= width / 2;
|
||||
width *= kHexByteWidth;
|
||||
} else
|
||||
left += hexWidth + (kBlockSpace * width);
|
||||
|
||||
int32 row = int32((point.y - kVerticalSpace) / fFontHeight);
|
||||
int32 column = int32((point.x - left) / width);
|
||||
if (column >= (int32)kBlockSize)
|
||||
column = (int32)kBlockSize -1;
|
||||
else if (column < 0)
|
||||
column = 0;
|
||||
|
||||
return row * kBlockSize + column;
|
||||
}
|
||||
|
||||
|
||||
BRect
|
||||
DataView::SelectionFrame(view_focus which, int32 start, int32 end)
|
||||
{
|
||||
float spacing = 0;
|
||||
float width = fCharWidth;
|
||||
float byteWidth = fCharWidth;
|
||||
float left;
|
||||
|
||||
if (which == kHexFocus) {
|
||||
spacing = fCharWidth / 2;
|
||||
left = width * (fPositionLength + kBlockSpace);
|
||||
width *= kHexByteWidth;
|
||||
byteWidth *= 2;
|
||||
} else
|
||||
left = width * (fPositionLength + 2 * kBlockSpace + kHexByteWidth * kBlockSize);
|
||||
|
||||
left += kHorizontalSpace;
|
||||
float startInLine = (start % kBlockSize) * width;
|
||||
float endInLine = (end % kBlockSize) * width + byteWidth - 1;
|
||||
|
||||
return BRect(left + startInLine - spacing,
|
||||
kVerticalSpace + (start / kBlockSize) * fFontHeight,
|
||||
left + endInLine + spacing,
|
||||
kVerticalSpace + (end / kBlockSize + 1) * fFontHeight - 1);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::DrawSelectionFrame(view_focus which)
|
||||
{
|
||||
bool drawBlock = false;
|
||||
bool drawLastLine = false;
|
||||
BRect block, lastLine;
|
||||
int32 spacing = 0;
|
||||
if (which == kAsciiFocus)
|
||||
spacing++;
|
||||
|
||||
// draw first line
|
||||
|
||||
int32 start = fStart % kBlockSize;
|
||||
int32 first = (fStart / kBlockSize) * kBlockSize;
|
||||
|
||||
int32 end = fEnd;
|
||||
if (end > first + (int32)kBlockSize - 1)
|
||||
end = first + kBlockSize - 1;
|
||||
|
||||
BRect firstLine = SelectionFrame(which, first + start, end);
|
||||
firstLine.right += spacing;
|
||||
first += kBlockSize;
|
||||
|
||||
// draw block (and last line) if necessary
|
||||
|
||||
end = fEnd % kBlockSize;
|
||||
int32 last = (fEnd / kBlockSize) * kBlockSize;
|
||||
|
||||
if (last >= first) {
|
||||
if (end == kBlockSize - 1)
|
||||
last += kBlockSize;
|
||||
if (last > first) {
|
||||
block = SelectionFrame(which, first, last - 1);
|
||||
block.right += spacing;
|
||||
drawBlock = true;
|
||||
}
|
||||
if (end != kBlockSize - 1) {
|
||||
lastLine = SelectionFrame(which, last, last + end);
|
||||
lastLine.right += spacing;
|
||||
drawLastLine = true;
|
||||
}
|
||||
}
|
||||
|
||||
SetDrawingMode(B_OP_INVERT);
|
||||
BeginLineArray(8);
|
||||
|
||||
// +*******
|
||||
// | *
|
||||
// +------+
|
||||
|
||||
const rgb_color color = {0, 0, 0};
|
||||
float bottom;
|
||||
if (drawBlock)
|
||||
bottom = block.bottom;
|
||||
else
|
||||
bottom = firstLine.bottom;
|
||||
|
||||
AddLine(BPoint(firstLine.left + 1, firstLine.top), firstLine.RightTop(), color);
|
||||
AddLine(BPoint(firstLine.right, firstLine.top + 1), BPoint(firstLine.right, bottom), color);
|
||||
|
||||
// *-------+
|
||||
// * |
|
||||
// *********
|
||||
|
||||
BRect rect;
|
||||
if (start == 0 || !drawBlock && !drawLastLine)
|
||||
rect = firstLine;
|
||||
else if (drawBlock)
|
||||
rect = block;
|
||||
else
|
||||
rect = lastLine;
|
||||
|
||||
if (drawBlock)
|
||||
rect.bottom = block.bottom;
|
||||
if (drawLastLine) {
|
||||
rect.bottom = lastLine.bottom;
|
||||
rect.right = lastLine.right;
|
||||
}
|
||||
rect.bottom++;
|
||||
|
||||
AddLine(rect.LeftTop(), rect.LeftBottom(), color);
|
||||
AddLine(BPoint(rect.left + 1, rect.bottom), rect.RightBottom(), color);
|
||||
|
||||
// *--------+
|
||||
// * |
|
||||
// +**** |
|
||||
// | |
|
||||
|
||||
if (start && (drawLastLine || drawBlock)) {
|
||||
AddLine(firstLine.LeftTop(), firstLine.LeftBottom(), color);
|
||||
|
||||
float right = firstLine.left;
|
||||
if (!drawBlock && right > lastLine.right)
|
||||
right = lastLine.right;
|
||||
AddLine(BPoint(rect.left + 1, rect.top), BPoint(right, rect.top), color);
|
||||
}
|
||||
|
||||
// | |
|
||||
// | *****
|
||||
// | *
|
||||
// +--------+
|
||||
|
||||
if (drawLastLine) {
|
||||
AddLine(lastLine.RightBottom(), BPoint(lastLine.right, lastLine.top + 1), color);
|
||||
if (!drawBlock && lastLine.right <= firstLine.left)
|
||||
lastLine.right = firstLine.left + (lastLine.right < firstLine.left ? 0 : 1);
|
||||
AddLine(BPoint(lastLine.right, lastLine.top), BPoint(firstLine.right, lastLine.top), color);
|
||||
}
|
||||
|
||||
EndLineArray();
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::DrawSelectionBlock(view_focus which)
|
||||
{
|
||||
// draw first line
|
||||
|
||||
SetDrawingMode(B_OP_INVERT);
|
||||
|
||||
int32 start = fStart % kBlockSize;
|
||||
int32 first = (fStart / kBlockSize) * kBlockSize;
|
||||
|
||||
int32 end = fEnd;
|
||||
if (end > first + (int32)kBlockSize - 1)
|
||||
end = first + kBlockSize - 1;
|
||||
|
||||
FillRect(SelectionFrame(which, first + start, end));
|
||||
first += kBlockSize;
|
||||
|
||||
// draw block (and last line) if necessary
|
||||
|
||||
end = fEnd % kBlockSize;
|
||||
int32 last = (fEnd / kBlockSize) * kBlockSize;
|
||||
|
||||
if (last >= first) {
|
||||
if (end == kBlockSize - 1)
|
||||
last += kBlockSize;
|
||||
|
||||
if (last > first)
|
||||
FillRect(SelectionFrame(which, first, last - 1));
|
||||
if (end != kBlockSize - 1)
|
||||
FillRect(SelectionFrame(which, last, last + end));
|
||||
}
|
||||
|
||||
SetDrawingMode(B_OP_COPY);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::DrawSelection()
|
||||
{
|
||||
if (fIsActive) {
|
||||
DrawSelectionBlock(fFocus);
|
||||
DrawSelectionFrame(fFocus == kHexFocus ? kAsciiFocus : kHexFocus);
|
||||
} else {
|
||||
DrawSelectionFrame(kHexFocus);
|
||||
DrawSelectionFrame(kAsciiFocus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::SetSelection(int32 start, int32 end, view_focus focus)
|
||||
{
|
||||
if (start > end) {
|
||||
int32 temp = start;
|
||||
start = end;
|
||||
end = temp;
|
||||
}
|
||||
|
||||
if (start < 0)
|
||||
start = 0;
|
||||
if (end > (int32)fDataSize - 1)
|
||||
end = (int32)fDataSize - 1;
|
||||
|
||||
if (fStart == start && fEnd == end) {
|
||||
// nothing has changed, no need to update
|
||||
return;
|
||||
}
|
||||
|
||||
// remove old selection
|
||||
// ToDo: this could be drastically improved if only the changed
|
||||
// parts are drawn! Of course, this would only work for the
|
||||
// selection block, not the frame.
|
||||
DrawSelection();
|
||||
|
||||
if (focus != kNoFocus)
|
||||
fFocus = focus;
|
||||
fStart = start;
|
||||
fEnd = end;
|
||||
|
||||
DrawSelection();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::GetSelection(int32 &start, int32 &end)
|
||||
{
|
||||
start = fStart;
|
||||
end = fEnd;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::InvalidateRange(int32 start, int32 end)
|
||||
{
|
||||
int32 startLine = start / kBlockSize;
|
||||
int32 endLine = end / kBlockSize;
|
||||
|
||||
if (endLine > startLine) {
|
||||
start = startLine * kBlockSize;
|
||||
end = (endLine + 1) * kBlockSize - 1;
|
||||
}
|
||||
|
||||
// the part with focus
|
||||
BRect rect = SelectionFrame(fFocus, start, end);
|
||||
rect.bottom++;
|
||||
rect.right++;
|
||||
Invalidate(rect);
|
||||
|
||||
// the part without focus
|
||||
rect = SelectionFrame(fFocus == kHexFocus ? kAsciiFocus : kHexFocus, start, end);
|
||||
rect.bottom++;
|
||||
rect.right++;
|
||||
Invalidate(rect);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::SetFocus(view_focus which)
|
||||
{
|
||||
if (which == fFocus)
|
||||
return;
|
||||
|
||||
DrawSelection();
|
||||
fFocus = which;
|
||||
DrawSelection();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::WindowActivated(bool active)
|
||||
{
|
||||
fIsActive = active;
|
||||
|
||||
// only redraw the focussed part
|
||||
|
||||
if (fIsActive) {
|
||||
DrawSelectionFrame(fFocus);
|
||||
DrawSelectionBlock(fFocus);
|
||||
} else {
|
||||
DrawSelectionBlock(fFocus);
|
||||
DrawSelectionFrame(fFocus);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::MouseDown(BPoint where)
|
||||
{
|
||||
BMessage *message = Looper()->CurrentMessage();
|
||||
int32 buttons;
|
||||
if (message == NULL || message->FindInt32("buttons", &buttons) != B_OK
|
||||
|| (buttons & B_PRIMARY_MOUSE_BUTTON) == 0)
|
||||
return;
|
||||
|
||||
int32 modifiers = message->FindInt32("modifiers");
|
||||
|
||||
view_focus newFocus;
|
||||
fMouseSelectionStart = PositionAt(kNoFocus, where, &newFocus);
|
||||
if (fMouseSelectionStart == -1) {
|
||||
// "where" is outside the valid frame
|
||||
return;
|
||||
}
|
||||
|
||||
int32 selectionEnd = fMouseSelectionStart;
|
||||
if (modifiers & B_SHIFT_KEY) {
|
||||
// enlarge the current selection
|
||||
if (fStart < selectionEnd)
|
||||
fMouseSelectionStart = fStart;
|
||||
else if (fEnd > selectionEnd)
|
||||
fMouseSelectionStart = fEnd;
|
||||
}
|
||||
SetSelection(fMouseSelectionStart, selectionEnd, newFocus);
|
||||
|
||||
SetMouseEventMask(B_POINTER_EVENTS,
|
||||
B_NO_POINTER_HISTORY | B_SUSPEND_VIEW_FOCUS | B_LOCK_WINDOW_FOCUS);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::MouseMoved(BPoint where, uint32 transit, const BMessage */*dragMessage*/)
|
||||
{
|
||||
if (fMouseSelectionStart == -1)
|
||||
return;
|
||||
|
||||
SetSelection(fMouseSelectionStart, PositionAt(fFocus, where));
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::MouseUp(BPoint where)
|
||||
{
|
||||
fMouseSelectionStart = -1;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DataView::SetFont(const BFont *font, uint32 properties)
|
||||
{
|
||||
if (!font->IsFixed())
|
||||
@@ -157,6 +541,7 @@ DataView::SetFont(const BFont *font, uint32 properties)
|
||||
|
||||
fFontHeight = int32(fontHeight.ascent + fontHeight.descent + fontHeight.leading);
|
||||
fAscent = fontHeight.ascent;
|
||||
fCharWidth = font->StringWidth("w");
|
||||
}
|
||||
|
||||
|
||||
@@ -176,7 +561,7 @@ DataView::GetPreferredSize(float *_width, float *_height)
|
||||
if (_width) {
|
||||
BFont font;
|
||||
GetFont(&font);
|
||||
*_width = font.StringWidth("w") * (kBlockSize * 4 + fPositionLength + 6)
|
||||
*_width = fCharWidth * (kBlockSize * 4 + fPositionLength + 6)
|
||||
+ 2 * kHorizontalSpace;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,6 +13,11 @@
|
||||
|
||||
class DataEditor;
|
||||
|
||||
enum view_focus {
|
||||
kNoFocus,
|
||||
kHexFocus,
|
||||
kAsciiFocus
|
||||
};
|
||||
|
||||
class DataView : public BView {
|
||||
public:
|
||||
@@ -24,22 +29,44 @@ class DataView : public BView {
|
||||
virtual void MessageReceived(BMessage *message);
|
||||
virtual void Draw(BRect updateRect);
|
||||
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit, const BMessage *message);
|
||||
virtual void MouseUp(BPoint where);
|
||||
|
||||
virtual void WindowActivated(bool active);
|
||||
virtual void SetFont(const BFont *font, uint32 properties = B_FONT_ALL);
|
||||
virtual void GetPreferredSize(float *_width, float *_height);
|
||||
|
||||
void SetFontSize(float point);
|
||||
|
||||
void SetSelection(int32 start, int32 end, view_focus focus = kNoFocus);
|
||||
void GetSelection(int32 &start, int32 &end);
|
||||
void InvalidateRange(int32 start, int32 end);
|
||||
|
||||
private:
|
||||
BRect SelectionFrame(view_focus which, int32 start, int32 end);
|
||||
int32 PositionAt(view_focus focus, BPoint point, view_focus *_newFocus = NULL);
|
||||
|
||||
void DrawSelectionFrame(view_focus which);
|
||||
void DrawSelectionBlock(view_focus which);
|
||||
void DrawSelection();
|
||||
void SetFocus(view_focus which);
|
||||
|
||||
void UpdateFromEditor(BMessage *message = NULL);
|
||||
void ConvertLine(char *line, off_t offset, const uint8 *buffer, size_t size);
|
||||
|
||||
DataEditor &fEditor;
|
||||
int32 fPositionLength;
|
||||
uint8 *fData;
|
||||
uint32 fDataSize;
|
||||
size_t fDataSize;
|
||||
off_t fOffset;
|
||||
float fAscent;
|
||||
int32 fFontHeight;
|
||||
float fCharWidth;
|
||||
view_focus fFocus;
|
||||
bool fIsActive;
|
||||
int32 fStart, fEnd;
|
||||
int32 fMouseSelectionStart;
|
||||
};
|
||||
|
||||
#endif /* DATA_VIEW_H */
|
||||
|
||||
Reference in New Issue
Block a user