From f6102c6fba34f639d328d3480948f21ec76f80c9 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Wed, 24 Aug 2011 22:06:24 +0000 Subject: [PATCH] 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 --- src/preferences/locale/LanguageListView.cpp | 104 +++++++++++++++----- src/preferences/locale/LanguageListView.h | 5 + src/preferences/locale/LocaleWindow.cpp | 38 ++++--- 3 files changed, 109 insertions(+), 38 deletions(-) diff --git a/src/preferences/locale/LanguageListView.cpp b/src/preferences/locale/LanguageListView.cpp index b823e893fe..9787ae00a4 100644 --- a/src/preferences/locale/LanguageListView.cpp +++ b/src/preferences/locale/LanguageListView.cpp @@ -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(FullListItemAt(index)); + = static_cast(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(); + } } diff --git a/src/preferences/locale/LanguageListView.h b/src/preferences/locale/LanguageListView.h index 8d0b0d9482..79f5fa1365 100644 --- a/src/preferences/locale/LanguageListView.h +++ b/src/preferences/locale/LanguageListView.h @@ -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; }; diff --git a/src/preferences/locale/LocaleWindow.cpp b/src/preferences/locale/LocaleWindow.cpp index 29b3180a6c..56757f9fe8 100644 --- a/src/preferences/locale/LocaleWindow.cpp +++ b/src/preferences/locale/LocaleWindow.cpp @@ -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( - 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( - fPreferredListView->FullListItemAt(index)); + fPreferredListView->ItemAt(index)); if (item != NULL) preferredLanguages.AddString("language", item->ID()); index++;