Icon-O-Matic: Fix crashes while auto-scrolling
This fixes crashes that happen when scrolling list views in Icon-O-Matic triggered by the BListView auto-scroll feature reintroduced in hrev57439. Take out the auto-scrolling code from Icon-O-Matic, call BListView's MouseMoved() instead since BListView's can scroll now. The BListView auto- scroll feature has been updated to work with draggable multi-select. ScrollTo(index) method has been moved from Icon-O-matic to BListView and is used to scroll to an index instead of a selection since the selection doesn't change while you are dragging. Override BListItem's DrawItem() method to prevent it from drawing. I've hijacked DrawItem()'s complete param to mean even or odd instead. Everybody draws the same background PathListView.cpp and StyleListView.cpp now push the frame over and draw text using SimpleListView parent class DrawItem() instead of repeating the drawing code. InitiateDrag got moved from the abstract DragSortableListView class to the SimpleListView implementation class. The following color constants have been added: rgb_color kDropIndicatorColor = make_color(255, 65, 54, 255); rgb_color kDragFrameColor = make_color(17, 17, 17, 255); First one is the red drop target indicator line. It has been changed to clrs.cc red which is the same as B_FAILURE_COLOR, but I didn't want to use that InterfaceDef constant as it doesn't indicate failure in this case, it's just a slightly different red. Second one is the drag selection outline, it has been changed from pure black to clrs.cc black which is a shade lighter than pure black. Fixes #18707 Change-Id: Ib0b375d7d5641d458a6ce004a6dfeac551636698 Reviewed-on: https://review.haiku-os.org/c/haiku/+/7215 Reviewed-by: waddlesplash <waddlesplash@gmail.com> Reviewed-by: Adrien Destugues <pulkomandy@pulkomandy.tk> Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
This commit is contained in:
parent
2f719499aa
commit
f99596f4e3
@ -33,9 +33,9 @@
|
||||
#define ALPHA 170
|
||||
#define TEXT_OFFSET 5.0
|
||||
|
||||
enum {
|
||||
MSG_TICK = 'tick',
|
||||
};
|
||||
|
||||
static const rgb_color kDropIndicatorColor = make_color(255, 65, 54, 255);
|
||||
static const rgb_color kDragFrameColor = make_color(17, 17, 17, 255);
|
||||
|
||||
|
||||
// #pragma mark - SimpleItem
|
||||
@ -54,9 +54,10 @@ SimpleItem::~SimpleItem()
|
||||
|
||||
|
||||
void
|
||||
SimpleItem::Draw(BView *owner, BRect frame, uint32 flags)
|
||||
SimpleItem::DrawItem(BView* owner, BRect itemFrame, bool even)
|
||||
{
|
||||
DrawBackground(owner, frame, flags);
|
||||
DrawBackground(owner, itemFrame, even);
|
||||
|
||||
// label
|
||||
if (IsSelected())
|
||||
owner->SetHighUIColor(B_LIST_SELECTED_ITEM_TEXT_COLOR);
|
||||
@ -69,13 +70,13 @@ SimpleItem::Draw(BView *owner, BRect frame, uint32 flags)
|
||||
const char* text = Text();
|
||||
BString truncatedString(text);
|
||||
owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE,
|
||||
frame.Width() - TEXT_OFFSET - 4);
|
||||
itemFrame.Width() - TEXT_OFFSET - 4);
|
||||
|
||||
float height = frame.Height();
|
||||
float height = itemFrame.Height();
|
||||
float textHeight = fh.ascent + fh.descent;
|
||||
BPoint textPoint;
|
||||
textPoint.x = frame.left + TEXT_OFFSET;
|
||||
textPoint.y = frame.top
|
||||
textPoint.x = itemFrame.left + TEXT_OFFSET;
|
||||
textPoint.y = itemFrame.top
|
||||
+ ceilf(height / 2 - textHeight / 2 + fh.ascent);
|
||||
|
||||
owner->DrawString(truncatedString.String(), textPoint);
|
||||
@ -83,25 +84,27 @@ SimpleItem::Draw(BView *owner, BRect frame, uint32 flags)
|
||||
|
||||
|
||||
void
|
||||
SimpleItem::DrawBackground(BView *owner, BRect frame, uint32 flags)
|
||||
SimpleItem::DrawBackground(BView* owner, BRect itemFrame, bool even)
|
||||
{
|
||||
// stroke a blue frame around the item if it's focused
|
||||
if (flags & FLAGS_FOCUSED) {
|
||||
owner->SetLowColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
owner->StrokeRect(frame, B_SOLID_LOW);
|
||||
frame.InsetBy(1.0, 1.0);
|
||||
}
|
||||
// figure out bg-color
|
||||
rgb_color color = ui_color(B_LIST_BACKGROUND_COLOR);
|
||||
rgb_color bgColor;
|
||||
if (!IsEnabled()) {
|
||||
rgb_color textColor = ui_color(B_LIST_ITEM_TEXT_COLOR);
|
||||
rgb_color disabledColor;
|
||||
if (textColor.red + textColor.green + textColor.blue > 128 * 3)
|
||||
disabledColor = tint_color(textColor, B_DARKEN_2_TINT);
|
||||
else
|
||||
disabledColor = tint_color(textColor, B_LIGHTEN_2_TINT);
|
||||
bgColor = disabledColor;
|
||||
} else if (IsSelected())
|
||||
bgColor = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR);
|
||||
else
|
||||
bgColor = ui_color(B_LIST_BACKGROUND_COLOR);
|
||||
|
||||
if (IsSelected())
|
||||
color = ui_color(B_LIST_SELECTED_BACKGROUND_COLOR);
|
||||
if (even)
|
||||
bgColor = tint_color(bgColor, 1.06);
|
||||
|
||||
if (flags & FLAGS_TINTED_LINE)
|
||||
color = tint_color(color, 1.06);
|
||||
|
||||
owner->SetLowColor(color);
|
||||
owner->FillRect(frame, B_SOLID_LOW);
|
||||
owner->SetLowColor(bgColor);
|
||||
owner->FillRect(itemFrame, B_SOLID_LOW);
|
||||
}
|
||||
|
||||
|
||||
@ -131,7 +134,6 @@ DragSortableListView::DragSortableListView(BRect frame, const char* name,
|
||||
DragSortableListView::~DragSortableListView()
|
||||
{
|
||||
delete fMouseWheelFilter;
|
||||
delete fScrollPulse;
|
||||
|
||||
SetSelection(NULL);
|
||||
}
|
||||
@ -166,54 +168,6 @@ DragSortableListView::FrameResized(float width, float height)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::Draw(BRect updateRect)
|
||||
{
|
||||
int32 firstIndex = IndexOf(updateRect.LeftTop());
|
||||
int32 lastIndex = IndexOf(updateRect.RightBottom());
|
||||
if (firstIndex >= 0) {
|
||||
if (lastIndex < firstIndex)
|
||||
lastIndex = CountItems() - 1;
|
||||
// update rect contains items
|
||||
BRect r = updateRect;
|
||||
for (int32 i = firstIndex; i <= lastIndex; i++) {
|
||||
r = ItemFrame(i);
|
||||
DrawListItem(this, i, r);
|
||||
}
|
||||
updateRect.top = r.bottom + 1.0;
|
||||
if (updateRect.IsValid()) {
|
||||
SetLowColor(ui_color(B_LIST_BACKGROUND_COLOR));
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
}
|
||||
} else {
|
||||
SetLowColor(ui_color(B_LIST_BACKGROUND_COLOR));
|
||||
FillRect(updateRect, B_SOLID_LOW);
|
||||
}
|
||||
// drop anticipation indication
|
||||
if (fDropRect.IsValid()) {
|
||||
SetHighColor(255, 0, 0, 255);
|
||||
StrokeRect(fDropRect);
|
||||
}
|
||||
/* // focus indication
|
||||
if (IsFocus()) {
|
||||
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
StrokeRect(Bounds());
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::ScrollTo(BPoint where)
|
||||
{
|
||||
uint32 buttons;
|
||||
BPoint point;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
BListView::ScrollTo(where);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::TargetedByScrollView(BScrollView* scrollView)
|
||||
{
|
||||
@ -222,103 +176,6 @@ DragSortableListView::TargetedByScrollView(BScrollView* scrollView)
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DragSortableListView::InitiateDrag(BPoint point, int32 index, bool)
|
||||
{
|
||||
// supress drag&drop while an item is focused
|
||||
if (fFocusedIndex >= 0)
|
||||
return false;
|
||||
|
||||
bool success = false;
|
||||
BListItem* item = ItemAt(CurrentSelection(0));
|
||||
if (!item) {
|
||||
// workarround a timing problem
|
||||
Select(index);
|
||||
item = ItemAt(index);
|
||||
}
|
||||
if (item) {
|
||||
// create drag message
|
||||
BMessage msg(fDragCommand);
|
||||
MakeDragMessage(&msg);
|
||||
// figure out drag rect
|
||||
float width = Bounds().Width();
|
||||
BRect dragRect(0.0, 0.0, width, -1.0);
|
||||
// figure out, how many items fit into our bitmap
|
||||
int32 numItems;
|
||||
bool fade = false;
|
||||
for (numItems = 0; BListItem* item = ItemAt(CurrentSelection(numItems)); numItems++) {
|
||||
dragRect.bottom += ceilf(item->Height()) + 1.0;
|
||||
if (dragRect.Height() > MAX_DRAG_HEIGHT) {
|
||||
fade = true;
|
||||
dragRect.bottom = MAX_DRAG_HEIGHT;
|
||||
numItems++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
BBitmap* dragBitmap = new BBitmap(dragRect, B_RGB32, true);
|
||||
if (dragBitmap && dragBitmap->IsValid()) {
|
||||
if (BView *v = new BView(dragBitmap->Bounds(), "helper",
|
||||
B_FOLLOW_NONE, B_WILL_DRAW)) {
|
||||
dragBitmap->AddChild(v);
|
||||
dragBitmap->Lock();
|
||||
BRect itemBounds(dragRect) ;
|
||||
itemBounds.bottom = 0.0;
|
||||
// let all selected items, that fit into our drag_bitmap, draw
|
||||
for (int32 i = 0; i < numItems; i++) {
|
||||
int32 index = CurrentSelection(i);
|
||||
BListItem* item = ItemAt(index);
|
||||
itemBounds.bottom = itemBounds.top + ceilf(item->Height());
|
||||
if (itemBounds.bottom > dragRect.bottom)
|
||||
itemBounds.bottom = dragRect.bottom;
|
||||
DrawListItem(v, index, itemBounds);
|
||||
itemBounds.top = itemBounds.bottom + 1.0;
|
||||
}
|
||||
// make a black frame arround the edge
|
||||
v->SetHighColor(0, 0, 0, 255);
|
||||
v->StrokeRect(v->Bounds());
|
||||
v->Sync();
|
||||
|
||||
uint8 *bits = (uint8 *)dragBitmap->Bits();
|
||||
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
|
||||
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
|
||||
int32 bpr = dragBitmap->BytesPerRow();
|
||||
|
||||
if (fade) {
|
||||
for (int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
for (int32 y = height - ALPHA / 2; y < height; y++, bits += bpr) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = (height - y) << 1;
|
||||
}
|
||||
} else {
|
||||
for (int32 y = 0; y < height; y++, bits += bpr) {
|
||||
uint8 *line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
}
|
||||
dragBitmap->Unlock();
|
||||
}
|
||||
} else {
|
||||
delete dragBitmap;
|
||||
dragBitmap = NULL;
|
||||
}
|
||||
if (dragBitmap)
|
||||
DragMessage(&msg, dragBitmap, B_OP_ALPHA, BPoint(0.0, 0.0));
|
||||
else
|
||||
DragMessage(&msg, dragRect.OffsetToCopy(point), this);
|
||||
|
||||
SetDragMessage(&msg);
|
||||
success = true;
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::WindowActivated(bool active)
|
||||
{
|
||||
@ -339,37 +196,6 @@ DragSortableListView::MessageReceived(BMessage* message)
|
||||
fDropIndex = -1;
|
||||
} else {
|
||||
switch (message->what) {
|
||||
case MSG_TICK: {
|
||||
float scrollV = 0.0;
|
||||
BRect rect(Bounds());
|
||||
BPoint point;
|
||||
uint32 buttons;
|
||||
GetMouse(&point, &buttons, false);
|
||||
if (rect.Contains(point)) {
|
||||
// calculate the vertical scrolling offset
|
||||
float hotDist = rect.Height() * SCROLL_AREA;
|
||||
if (point.y > rect.bottom - hotDist)
|
||||
scrollV = hotDist - (rect.bottom - point.y);
|
||||
else if (point.y < rect.top + hotDist)
|
||||
scrollV = (point.y - rect.top) - hotDist;
|
||||
}
|
||||
// scroll
|
||||
if (scrollV != 0.0 && fScrollView) {
|
||||
if (BScrollBar* scrollBar = fScrollView->ScrollBar(B_VERTICAL)) {
|
||||
float value = scrollBar->Value();
|
||||
scrollBar->SetValue(scrollBar->Value() + scrollV);
|
||||
if (scrollBar->Value() != value) {
|
||||
// update mouse position
|
||||
uint32 buttons;
|
||||
BPoint point;
|
||||
GetMouse(&point, &buttons, false);
|
||||
uint32 transit = Bounds().Contains(point) ? B_INSIDE_VIEW : B_OUTSIDE_VIEW;
|
||||
MouseMoved(point, transit, &fDragMessageCopy);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case B_MOUSE_WHEEL_CHANGED:
|
||||
{
|
||||
BListView::MessageReceived(message);
|
||||
@ -405,35 +231,34 @@ DragSortableListView::KeyDown(const char* bytes, int32 numBytes)
|
||||
void
|
||||
DragSortableListView::MouseDown(BPoint where)
|
||||
{
|
||||
int32 clicks = 1;
|
||||
uint32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("clicks", &clicks);
|
||||
Window()->CurrentMessage()->FindInt32("buttons", (int32*)&buttons);
|
||||
int32 clickedIndex = -1;
|
||||
for (int32 i = 0; BListItem* item = ItemAt(i); i++) {
|
||||
if (ItemFrame(i).Contains(where)) {
|
||||
if (clicks == 2) {
|
||||
// only do something if user clicked the same item twice
|
||||
if (fLastClickedItem == item)
|
||||
DoubleClicked(i);
|
||||
} else {
|
||||
// remember last clicked item
|
||||
fLastClickedItem = item;
|
||||
}
|
||||
clickedIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (clickedIndex == -1)
|
||||
fLastClickedItem = NULL;
|
||||
int32 index = IndexOf(where);
|
||||
BListItem* item = ItemAt(index);
|
||||
|
||||
BListItem* item = ItemAt(clickedIndex);
|
||||
if (ListType() == B_MULTIPLE_SELECTION_LIST && item != NULL
|
||||
&& (buttons & B_SECONDARY_MOUSE_BUTTON)) {
|
||||
// bail out if item not found
|
||||
if (index < 0 || item == NULL) {
|
||||
fLastClickedItem = NULL;
|
||||
return BListView::MouseDown(where);
|
||||
}
|
||||
|
||||
int32 clicks = 1;
|
||||
int32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("clicks", &clicks);
|
||||
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
|
||||
|
||||
if (clicks == 2 && item == fLastClickedItem) {
|
||||
// only do something if user clicked the same item twice
|
||||
DoubleClicked(index);
|
||||
} else {
|
||||
// remember last clicked item
|
||||
fLastClickedItem = item;
|
||||
}
|
||||
|
||||
if (ListType() == B_MULTIPLE_SELECTION_LIST
|
||||
&& (buttons & B_SECONDARY_MOUSE_BUTTON) != 0) {
|
||||
if (item->IsSelected())
|
||||
Deselect(clickedIndex);
|
||||
Deselect(index);
|
||||
else
|
||||
Select(clickedIndex, true);
|
||||
Select(index, true);
|
||||
} else
|
||||
BListView::MouseDown(where);
|
||||
}
|
||||
@ -442,40 +267,42 @@ DragSortableListView::MouseDown(BPoint where)
|
||||
void
|
||||
DragSortableListView::MouseMoved(BPoint where, uint32 transit, const BMessage* msg)
|
||||
{
|
||||
if (msg && AcceptDragMessage(msg)) {
|
||||
int32 buttons = 0;
|
||||
Window()->CurrentMessage()->FindInt32("buttons", &buttons);
|
||||
|
||||
// only start a drag if a button is down and we have a drag message
|
||||
if (buttons > 0 && msg && AcceptDragMessage(msg)) {
|
||||
// we have dragged off the mouse down item
|
||||
// turn on auto-scrolling and drag and drop
|
||||
switch (transit) {
|
||||
case B_ENTERED_VIEW:
|
||||
case B_INSIDE_VIEW: {
|
||||
// remember drag message
|
||||
// this is needed to react on modifier changes
|
||||
case B_INSIDE_VIEW:
|
||||
// remember drag message to react on modifier changes
|
||||
SetDragMessage(msg);
|
||||
// set drop target through virtual function
|
||||
SetDropTargetRect(msg, where);
|
||||
// go into autoscrolling mode
|
||||
BRect r = Bounds();
|
||||
r.InsetBy(0.0, r.Height() * SCROLL_AREA);
|
||||
SetAutoScrolling(!r.Contains(where));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case B_EXITED_VIEW:
|
||||
// forget drag message
|
||||
SetDragMessage(NULL);
|
||||
SetAutoScrolling(false);
|
||||
// fall through
|
||||
case B_OUTSIDE_VIEW:
|
||||
// don't draw drop rect indicator
|
||||
InvalidateDropRect();
|
||||
case B_OUTSIDE_VIEW:
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
InvalidateDropRect();
|
||||
BListView::MouseMoved(where, transit, msg);
|
||||
// be sure to forget drag message
|
||||
SetDragMessage(NULL);
|
||||
SetAutoScrolling(false);
|
||||
|
||||
// don't draw drop rect indicator
|
||||
InvalidateDropRect();
|
||||
// restore hand cursor
|
||||
BCursor cursor(B_HAND_CURSOR);
|
||||
SetViewCursor(&cursor, true);
|
||||
}
|
||||
|
||||
fLastMousePos = where;
|
||||
BListView::MouseMoved(where, transit, msg);
|
||||
}
|
||||
|
||||
|
||||
@ -494,17 +321,6 @@ DragSortableListView::MouseUp(BPoint where)
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::DrawItem(BListItem *item, BRect itemFrame, bool complete)
|
||||
{
|
||||
DrawListItem(this, IndexOf(item), itemFrame);
|
||||
/* if (IsFocus()) {
|
||||
SetHighColor(ui_color(B_KEYBOARD_NAVIGATION_COLOR));
|
||||
StrokeRect(Bounds());
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DragSortableListView::MouseWheelChanged(float x, float y)
|
||||
{
|
||||
@ -654,46 +470,10 @@ DragSortableListView::HandleDropMessage(const BMessage* message,
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::SetAutoScrolling(bool enable)
|
||||
{
|
||||
if (fScrollPulse && enable)
|
||||
return;
|
||||
if (enable) {
|
||||
BMessenger messenger(this, Window());
|
||||
BMessage message(MSG_TICK);
|
||||
fScrollPulse = new BMessageRunner(messenger, &message, 40000LL);
|
||||
} else {
|
||||
delete fScrollPulse;
|
||||
fScrollPulse = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
DragSortableListView::DoesAutoScrolling() const
|
||||
{
|
||||
return fScrollPulse;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
DragSortableListView::ScrollTo(int32 index)
|
||||
{
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
if (index >= CountItems())
|
||||
index = CountItems() - 1;
|
||||
|
||||
if (ItemAt(index)) {
|
||||
BRect itemFrame = ItemFrame(index);
|
||||
BRect bounds = Bounds();
|
||||
if (itemFrame.top < bounds.top) {
|
||||
ScrollTo(itemFrame.LeftTop());
|
||||
} else if (itemFrame.bottom > bounds.bottom) {
|
||||
ScrollTo(BPoint(0.0, itemFrame.bottom - bounds.Height()));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@ -974,6 +754,152 @@ SimpleListView::DetachedFromWindow()
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleListView::Draw(BRect updateRect)
|
||||
{
|
||||
BRect emptyRect = updateRect;
|
||||
|
||||
int32 firstIndex = IndexOf(updateRect.LeftTop());
|
||||
int32 lastIndex = IndexOf(updateRect.RightBottom());
|
||||
if (firstIndex >= 0) {
|
||||
BListItem* item;
|
||||
BRect itemFrame(0, 0, -1, -1);
|
||||
if (lastIndex < firstIndex)
|
||||
lastIndex = CountItems() - 1;
|
||||
// update rect contains items
|
||||
for (int32 i = firstIndex; i <= lastIndex; i++) {
|
||||
item = ItemAt(i);
|
||||
if (item == NULL)
|
||||
continue;
|
||||
itemFrame = ItemFrame(i);
|
||||
item->DrawItem(this, itemFrame, (i % 2) == 0);
|
||||
|
||||
// drop indicator
|
||||
if (i == fDropIndex) {
|
||||
SetHighColor(kDropIndicatorColor);
|
||||
StrokeLine(fDropRect.LeftTop(), fDropRect.RightTop());
|
||||
}
|
||||
}
|
||||
emptyRect.top = itemFrame.bottom + 1;
|
||||
}
|
||||
|
||||
if (emptyRect.IsValid()) {
|
||||
SetLowUIColor(B_LIST_BACKGROUND_COLOR);
|
||||
FillRect(emptyRect, B_SOLID_LOW);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// focus indicator
|
||||
if (IsFocus()) {
|
||||
SetHighUIColor(B_KEYBOARD_NAVIGATION_COLOR);
|
||||
StrokeRect(Bounds());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SimpleListView::InitiateDrag(BPoint where, int32 index, bool)
|
||||
{
|
||||
// supress drag & drop while an item is focused
|
||||
if (fFocusedIndex >= 0)
|
||||
return false;
|
||||
|
||||
BListItem* item = ItemAt(CurrentSelection(0));
|
||||
if (item == NULL) {
|
||||
// work-around a timing problem
|
||||
Select(index);
|
||||
item = ItemAt(index);
|
||||
}
|
||||
if (item == NULL)
|
||||
return false;
|
||||
|
||||
// create drag message
|
||||
BMessage msg(fDragCommand);
|
||||
MakeDragMessage(&msg);
|
||||
// figure out drag rect
|
||||
float width = Bounds().Width();
|
||||
BRect dragRect(0, 0, width, -1);
|
||||
// figure out how many items fit into our bitmap
|
||||
int32 numItems;
|
||||
bool fade = false;
|
||||
for (numItems = 0; BListItem* item = ItemAt(CurrentSelection(numItems)); numItems++) {
|
||||
dragRect.bottom += ceilf(item->Height()) + 1;
|
||||
if (dragRect.Height() > MAX_DRAG_HEIGHT) {
|
||||
fade = true;
|
||||
dragRect.bottom = MAX_DRAG_HEIGHT;
|
||||
numItems++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BBitmap* dragBitmap = new BBitmap(dragRect, B_RGBA32, true);
|
||||
if (dragBitmap && dragBitmap->IsValid()) {
|
||||
if (BView* view = new BView(dragBitmap->Bounds(), "helper",
|
||||
B_FOLLOW_NONE, B_WILL_DRAW)) {
|
||||
dragBitmap->AddChild(view);
|
||||
dragBitmap->Lock();
|
||||
BRect itemFrame(dragRect) ;
|
||||
itemFrame.bottom = 0.0;
|
||||
BListItem* item;
|
||||
// let all selected items, that fit into our drag_bitmap, draw
|
||||
for (int32 i = 0; i < numItems; i++) {
|
||||
item = ItemAt(CurrentSelection(i));
|
||||
if (item == NULL)
|
||||
continue;
|
||||
itemFrame.bottom = itemFrame.top + ceilf(item->Height());
|
||||
if (itemFrame.bottom > dragRect.bottom)
|
||||
itemFrame.bottom = dragRect.bottom;
|
||||
item->DrawItem(view, itemFrame, (i % 2) == 0);
|
||||
itemFrame.top = itemFrame.bottom + 1;
|
||||
}
|
||||
|
||||
// stroke a black frame around the edge
|
||||
view->SetHighColor(kDragFrameColor);
|
||||
view->StrokeRect(view->Bounds());
|
||||
view->Sync();
|
||||
|
||||
uint8* bits = (uint8*)dragBitmap->Bits();
|
||||
int32 height = (int32)dragBitmap->Bounds().Height() + 1;
|
||||
int32 width = (int32)dragBitmap->Bounds().Width() + 1;
|
||||
int32 bpr = dragBitmap->BytesPerRow();
|
||||
|
||||
if (fade) {
|
||||
for (int32 y = 0; y < height - ALPHA / 2; y++, bits += bpr) {
|
||||
uint8* line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
for (int32 y = height - ALPHA / 2; y < height; y++, bits += bpr) {
|
||||
uint8* line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = (height - y) << 1;
|
||||
}
|
||||
} else {
|
||||
for (int32 y = 0; y < height; y++, bits += bpr) {
|
||||
uint8* line = bits + 3;
|
||||
for (uint8 *end = line + 4 * width; line < end; line += 4)
|
||||
*line = ALPHA;
|
||||
}
|
||||
}
|
||||
dragBitmap->Unlock();
|
||||
}
|
||||
} else {
|
||||
delete dragBitmap;
|
||||
dragBitmap = NULL;
|
||||
}
|
||||
|
||||
if (dragBitmap)
|
||||
DragMessage(&msg, dragBitmap, B_OP_ALPHA, B_ORIGIN);
|
||||
else
|
||||
DragMessage(&msg, dragRect.OffsetToCopy(where), this);
|
||||
|
||||
SetDragMessage(&msg);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleListView::MessageReceived(BMessage* message)
|
||||
{
|
||||
@ -1026,20 +952,6 @@ SimpleListView::CloneItem(int32 atIndex) const
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleListView::DrawListItem(BView* owner, int32 index, BRect frame) const
|
||||
{
|
||||
if (SimpleItem* item = dynamic_cast<SimpleItem*>(ItemAt(index))) {
|
||||
uint32 flags = FLAGS_NONE;
|
||||
if (index == fFocusedIndex)
|
||||
flags |= FLAGS_FOCUSED;
|
||||
if (index % 2)
|
||||
flags |= FLAGS_TINTED_LINE;
|
||||
item->Draw(owner, frame, flags);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SimpleListView::MakeDragMessage(BMessage* message) const
|
||||
{
|
||||
|
@ -17,13 +17,6 @@
|
||||
#include "MouseWheelFilter.h"
|
||||
#include "Observer.h"
|
||||
|
||||
enum
|
||||
{
|
||||
FLAGS_NONE = 0x00,
|
||||
FLAGS_TINTED_LINE = 0x01,
|
||||
FLAGS_FOCUSED = 0x02,
|
||||
};
|
||||
|
||||
// portion of the listviews height that triggers autoscrolling
|
||||
// when the mouse is over it with a dragmessage
|
||||
#define SCROLL_AREA 0.1
|
||||
@ -41,10 +34,8 @@ class SimpleItem : public BStringItem
|
||||
SimpleItem(const char* name);
|
||||
virtual ~SimpleItem();
|
||||
|
||||
virtual void Draw(BView* owner, BRect frame,
|
||||
uint32 flags);
|
||||
virtual void DrawBackground(BView* owner, BRect frame,
|
||||
uint32 flags);
|
||||
virtual void DrawItem(BView*, BRect, bool even = false);
|
||||
virtual void DrawBackground(BView*, BRect, bool even);
|
||||
};
|
||||
|
||||
|
||||
@ -65,20 +56,13 @@ class DragSortableListView : public BListView,
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void FrameResized(float width, float height);
|
||||
// virtual void MakeFocus(bool focused);
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual void ScrollTo(BPoint where);
|
||||
virtual void TargetedByScrollView(BScrollView* scrollView);
|
||||
virtual bool InitiateDrag(BPoint point, int32 index,
|
||||
bool wasSelected);
|
||||
virtual void TargetedByScrollView(BScrollView*);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
virtual void KeyDown(const char* bytes, int32 numBytes);
|
||||
virtual void MouseDown(BPoint where);
|
||||
virtual void MouseMoved(BPoint where, uint32 transit,
|
||||
const BMessage* dragMessage);
|
||||
virtual void MouseMoved(BPoint where, uint32, const BMessage*);
|
||||
virtual void MouseUp(BPoint where);
|
||||
virtual void WindowActivated(bool active);
|
||||
virtual void DrawItem(BListItem *item, BRect itemFrame,
|
||||
bool complete = false);
|
||||
|
||||
// MouseWheelTarget interface
|
||||
virtual bool MouseWheelChanged(float x, float y);
|
||||
@ -99,12 +83,9 @@ class DragSortableListView : public BListView,
|
||||
virtual void SetDropTargetRect(const BMessage* message,
|
||||
BPoint where);
|
||||
|
||||
// autoscrolling
|
||||
void SetAutoScrolling(bool enable);
|
||||
bool DoesAutoScrolling() const;
|
||||
BScrollView* ScrollView() const
|
||||
{ return fScrollView; }
|
||||
void ScrollTo(int32 index);
|
||||
|
||||
virtual void MoveItems(BList& items, int32 toIndex);
|
||||
virtual void CopyItems(BList& items, int32 toIndex);
|
||||
@ -125,8 +106,6 @@ class DragSortableListView : public BListView,
|
||||
virtual void SelectionChanged();
|
||||
|
||||
virtual BListItem* CloneItem(int32 atIndex) const = 0;
|
||||
virtual void DrawListItem(BView* owner, int32 index,
|
||||
BRect itemFrame) const = 0;
|
||||
virtual void MakeDragMessage(BMessage* message) const = 0;
|
||||
|
||||
protected:
|
||||
@ -170,11 +149,11 @@ class SimpleListView : public DragSortableListView {
|
||||
|
||||
// BListView
|
||||
virtual void DetachedFromWindow();
|
||||
virtual void Draw(BRect updateRect);
|
||||
virtual bool InitiateDrag(BPoint, int32, bool);
|
||||
virtual void MessageReceived(BMessage* message);
|
||||
|
||||
virtual BListItem* CloneItem(int32 atIndex) const;
|
||||
virtual void DrawListItem(BView* owner, int32 index,
|
||||
BRect itemFrame) const;
|
||||
|
||||
/*! Archive the selected items.
|
||||
The information should be sufficient for \c InstantiateSelection to
|
||||
|
@ -70,27 +70,12 @@ public:
|
||||
|
||||
|
||||
// SimpleItem interface
|
||||
virtual void Draw(BView* owner, BRect itemFrame, uint32 flags)
|
||||
virtual void DrawItem(BView* owner, BRect itemFrame, bool even)
|
||||
{
|
||||
SimpleItem::DrawBackground(owner, itemFrame, flags);
|
||||
SimpleItem::DrawBackground(owner, itemFrame, even);
|
||||
|
||||
// text
|
||||
if (IsSelected())
|
||||
owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
|
||||
else
|
||||
owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
|
||||
font_height fh;
|
||||
owner->GetFontHeight(&fh);
|
||||
BString truncatedString(Text());
|
||||
owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE,
|
||||
itemFrame.Width() - kBorderOffset - kMarkWidth - kTextOffset
|
||||
- kBorderOffset);
|
||||
float height = itemFrame.Height();
|
||||
float textHeight = fh.ascent + fh.descent;
|
||||
BPoint pos;
|
||||
pos.x = itemFrame.left + kBorderOffset + kMarkWidth + kTextOffset;
|
||||
pos.y = itemFrame.top + ceilf((height - textHeight) / 2.0 + fh.ascent);
|
||||
owner->DrawString(truncatedString.String(), pos);
|
||||
float offset = kBorderOffset + kMarkWidth + kTextOffset;
|
||||
SimpleItem::DrawItem(owner, itemFrame.OffsetByCopy(offset, 0), even);
|
||||
|
||||
if (!fMarkEnabled)
|
||||
return;
|
||||
|
@ -76,27 +76,12 @@ public:
|
||||
}
|
||||
|
||||
// SimpleItem interface
|
||||
virtual void Draw(BView* owner, BRect itemFrame, uint32 flags)
|
||||
virtual void DrawItem(BView* owner, BRect itemFrame, bool even)
|
||||
{
|
||||
SimpleItem::DrawBackground(owner, itemFrame, flags);
|
||||
SimpleItem::DrawBackground(owner, itemFrame, even);
|
||||
|
||||
// text
|
||||
if (IsSelected())
|
||||
owner->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR));
|
||||
else
|
||||
owner->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR));
|
||||
font_height fh;
|
||||
owner->GetFontHeight(&fh);
|
||||
BString truncatedString(Text());
|
||||
owner->TruncateString(&truncatedString, B_TRUNCATE_MIDDLE,
|
||||
itemFrame.Width() - kBorderOffset - kMarkWidth - kTextOffset
|
||||
- kBorderOffset);
|
||||
float height = itemFrame.Height();
|
||||
float textHeight = fh.ascent + fh.descent;
|
||||
BPoint pos;
|
||||
pos.x = itemFrame.left + kBorderOffset + kMarkWidth + kTextOffset;
|
||||
pos.y = itemFrame.top + ceilf((height - textHeight) / 2.0 + fh.ascent);
|
||||
owner->DrawString(truncatedString.String(), pos);
|
||||
float offset = kBorderOffset + kMarkWidth + kTextOffset;
|
||||
SimpleItem::DrawItem(owner, itemFrame.OffsetByCopy(offset, 0), even);
|
||||
|
||||
if (!fMarkEnabled)
|
||||
return;
|
||||
|
Loading…
Reference in New Issue
Block a user