Improve drag'n'drop in Locale preflet:

* following a hint by Stephan: implement drawing of a drop target indicator,
  a global one (bounds) for the available languages and an individual drop target 
  indicator ("between" the items) for the preferred languages
* fix drag'n'drop within preferred languages listview
* finish support for manipulating multiple items in preferred languages listview


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@42686 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Oliver Tappe 2011-08-24 22:06:24 +00:00
parent fdecfdb35c
commit f6102c6fba
3 changed files with 109 additions and 38 deletions

View File

@ -62,25 +62,21 @@ void
LanguageListItem::DrawItemWithTextOffset(BView* owner, BRect frame,
bool complete, float textOffset)
{
static const rgb_color kHighlight = {140, 140, 140, 0};
static const rgb_color kBlack = {0, 0, 0, 0};
if (IsSelected() || complete) {
rgb_color color;
if (IsSelected())
color = kHighlight;
color = ui_color(B_MENU_SELECTED_BACKGROUND_COLOR);
else
color = owner->ViewColor();
owner->SetHighColor(color);
owner->SetLowColor(color);
owner->FillRect(frame);
owner->SetHighColor(kBlack);
} else
owner->SetLowColor(owner->ViewColor());
BString text = Text();
if (IsEnabled())
owner->SetHighColor(kBlack);
owner->SetHighColor(ui_color(B_CONTROL_TEXT_COLOR));
else {
owner->SetHighColor(tint_color(owner->LowColor(), B_DARKEN_3_TINT));
text << " [" << B_TRANSLATE("already chosen") << "]";
@ -168,6 +164,8 @@ LanguageListView::LanguageListView(const char* name, list_view_type type)
:
BOutlineListView(name, type),
fDropIndex(-1),
fDropTargetHighlightFrame(),
fGlobalDropTargetIndicator(false),
fDeleteMessage(NULL),
fDragMessage(NULL)
{
@ -231,6 +229,13 @@ LanguageListView::SetDragMessage(BMessage* message)
}
void
LanguageListView::SetGlobalDropTargetIndicator(bool isGlobal)
{
fGlobalDropTargetIndicator = isGlobal;
}
void
LanguageListView::AttachedToWindow()
{
@ -247,13 +252,24 @@ LanguageListView::MessageReceived(BMessage* message)
BMessage dragMessage(*message);
dragMessage.AddInt32("drop_index", fDropIndex);
dragMessage.AddPointer("drop_target", this);
Invoke(&dragMessage);
Messenger().SendMessage(&dragMessage);
} else
BOutlineListView::MessageReceived(message);
}
void
LanguageListView::Draw(BRect updateRect)
{
BOutlineListView::Draw(updateRect);
if (fDropIndex >= 0 && fDropTargetHighlightFrame.IsValid()) {
SetHighColor(ui_color(B_CONTROL_HIGHLIGHT_COLOR));
StrokeRect(fDropTargetHighlightFrame);
}
}
bool
LanguageListView::InitiateDrag(BPoint point, int32 dragIndex,
bool /*wasSelected*/)
@ -261,7 +277,7 @@ LanguageListView::InitiateDrag(BPoint point, int32 dragIndex,
if (fDragMessage == NULL)
return false;
BListItem* item = FullListItemAt(CurrentSelection(0));
BListItem* item = ItemAt(CurrentSelection(0));
if (item == NULL) {
// workaround for a timing problem
// TODO: this should support extending the selection
@ -276,7 +292,7 @@ LanguageListView::InitiateDrag(BPoint point, int32 dragIndex,
message.AddPointer("listview", this);
for (int32 i = 0;; i++) {
int32 index = FullListCurrentSelection(i);
int32 index = CurrentSelection(i);
if (index < 0)
break;
@ -292,7 +308,7 @@ LanguageListView::InitiateDrag(BPoint point, int32 dragIndex,
// figure out, how many items fit into our bitmap
for (int32 i = 0, index; message.FindInt32("index", i, &index) == B_OK;
i++) {
BListItem* item = FullListItemAt(index);
BListItem* item = ItemAt(index);
if (item == NULL)
break;
@ -318,7 +334,7 @@ LanguageListView::InitiateDrag(BPoint point, int32 dragIndex,
for (int32 i = 0; i < numItems; i++) {
int32 index = message.FindInt32("index", i);
LanguageListItem* item
= static_cast<LanguageListItem*>(FullListItemAt(index));
= static_cast<LanguageListItem*>(ItemAt(index));
itemBounds.bottom = itemBounds.top + ceilf(item->Height());
if (itemBounds.bottom > dragRect.bottom)
itemBounds.bottom = dragRect.bottom;
@ -378,21 +394,63 @@ LanguageListView::MouseMoved(BPoint where, uint32 transit,
case B_ENTERED_VIEW:
case B_INSIDE_VIEW:
{
// set drop target through virtual function
// offset where by half of item height
BRect r = ItemFrame(0);
where.y += r.Height() / 2.0;
BRect highlightFrame;
int32 index = FullListIndexOf(where);
if (index < 0)
index = FullListCountItems();
if (fDropIndex != index)
if (fGlobalDropTargetIndicator) {
highlightFrame = Bounds();
fDropIndex = 0;
} else {
// offset where by half of item height
BRect r = ItemFrame(0);
where.y += r.Height() / 2.0;
int32 index = IndexOf(where);
if (index < 0)
index = CountItems();
highlightFrame = ItemFrame(index);
if (highlightFrame.IsValid())
highlightFrame.bottom = highlightFrame.top;
else {
highlightFrame = ItemFrame(index - 1);
if (highlightFrame.IsValid())
highlightFrame.top = highlightFrame.bottom;
else {
// empty view, show indicator at top
highlightFrame = Bounds();
highlightFrame.bottom = highlightFrame.top;
}
}
fDropIndex = index;
break;
}
if (fDropTargetHighlightFrame != highlightFrame) {
Invalidate(fDropTargetHighlightFrame);
fDropTargetHighlightFrame = highlightFrame;
Invalidate(fDropTargetHighlightFrame);
}
BOutlineListView::MouseMoved(where, transit, dragMessage);
return;
}
}
} else
BOutlineListView::MouseMoved(where, transit, dragMessage);
}
if (fDropTargetHighlightFrame.IsValid()) {
Invalidate(fDropTargetHighlightFrame);
fDropTargetHighlightFrame = BRect();
}
BOutlineListView::MouseMoved(where, transit, dragMessage);
}
void
LanguageListView::MouseUp(BPoint point)
{
BOutlineListView::MouseUp(point);
if (fDropTargetHighlightFrame.IsValid()) {
Invalidate(fDropTargetHighlightFrame);
fDropTargetHighlightFrame = BRect();
}
}

View File

@ -74,11 +74,14 @@ public:
void SetDeleteMessage(BMessage* message);
void SetDragMessage(BMessage* message);
void SetGlobalDropTargetIndicator(bool isGlobal);
virtual void Draw(BRect updateRect);
virtual bool InitiateDrag(BPoint point, int32 index,
bool wasSelected);
virtual void MouseMoved(BPoint where, uint32 transit,
const BMessage* dragMessage);
virtual void MouseUp(BPoint point);
virtual void AttachedToWindow();
virtual void MessageReceived(BMessage* message);
virtual void KeyDown(const char* bytes, int32 numBytes);
@ -89,6 +92,8 @@ private:
private:
int32 fDropIndex;
BRect fDropTargetHighlightFrame;
bool fGlobalDropTargetIndicator;
BMessage* fDeleteMessage;
BMessage* fDragMessage;
};

View File

@ -89,6 +89,7 @@ LocaleWindow::LocaleWindow()
fLanguageListView->SetInvocationMessage(new BMessage(kMsgLanguageInvoked));
fLanguageListView->SetDragMessage(new BMessage(kMsgLanguageDragged));
fLanguageListView->SetGlobalDropTargetIndicator(true);
BFont font;
fLanguageListView->GetFont(&font);
@ -335,7 +336,7 @@ LocaleWindow::MessageReceived(BMessage* message)
for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
i++) {
LanguageListItem* item = static_cast<LanguageListItem*>(
fLanguageListView->FullListItemAt(index));
fLanguageListView->ItemAt(index));
_InsertPreferredLanguage(item, dropIndex++);
}
break;
@ -363,15 +364,18 @@ LocaleWindow::MessageReceived(BMessage* message)
// change ordering
int32 dropIndex = message->FindInt32("drop_index");
int32 index = 0;
if (message->FindInt32("index", &index) == B_OK
&& dropIndex != index) {
for (int32 i = 0;
message->FindInt32("index", i, &index) == B_OK;
i++, dropIndex++) {
if (dropIndex > index) {
dropIndex--;
index -= i;
}
BListItem* item = fPreferredListView->RemoveItem(index);
if (dropIndex > index)
index--;
fPreferredListView->AddItem(item, dropIndex);
_PreferredLanguagesChanged();
}
_PreferredLanguagesChanged();
break;
}
@ -385,13 +389,18 @@ LocaleWindow::MessageReceived(BMessage* message)
// Remove from preferred languages
int32 index = 0;
if (message->FindInt32("index", &index) == B_OK) {
delete fPreferredListView->RemoveItem(index);
_PreferredLanguagesChanged();
for (int32 i = 0; message->FindInt32("index", i, &index) == B_OK;
i++) {
delete fPreferredListView->RemoveItem(index - i);
if (message->what == kMsgPreferredLanguageDeleted)
fPreferredListView->Select(index);
if (message->what == kMsgPreferredLanguageDeleted) {
int32 count = fPreferredListView->CountItems();
fPreferredListView->Select(
index < count ? index : count - 1);
}
}
_PreferredLanguagesChanged();
break;
}
@ -495,10 +504,9 @@ LocaleWindow::_PreferredLanguagesChanged()
{
BMessage preferredLanguages;
int index = 0;
while (index < fPreferredListView->FullListCountItems()) {
// only include subitems: we can guess the superitem from them anyway
while (index < fPreferredListView->CountItems()) {
LanguageListItem* item = static_cast<LanguageListItem*>(
fPreferredListView->FullListItemAt(index));
fPreferredListView->ItemAt(index));
if (item != NULL)
preferredLanguages.AddString("language", item->ID());
index++;