2 * Copyright 2006-2010, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Stephan Aßmus <superstippi@gmx.de>
7 * Adrien Destugues <pulkomandy@gmail.com>
8 * Axel Dörfler, axeld@pinc-software.de
9 * Oliver Tappe <zooey@hirschkaefer.de>
13 #include "LanguageListView.h"
21 #include <ControlLook.h>
22 #include <FormattingConventions.h>
23 #include <GradientLinear.h>
24 #include <LocaleRoster.h>
29 #define MAX_DRAG_HEIGHT 200.0
32 #undef B_TRANSLATION_CONTEXT
33 #define B_TRANSLATION_CONTEXT "LanguageListView"
36 LanguageListItem::LanguageListItem(const char* text
, const char* id
,
37 const char* languageCode
)
46 LanguageListItem::LanguageListItem(const LanguageListItem
& other
)
48 BStringItem(other
.Text()),
56 LanguageListItem::DrawItem(BView
* owner
, BRect frame
, bool complete
)
58 DrawItemWithTextOffset(owner
, frame
, complete
, 0);
63 LanguageListItem::DrawItemWithTextOffset(BView
* owner
, BRect frame
,
64 bool complete
, float textOffset
)
66 rgb_color highColor
= owner
->HighColor();
67 rgb_color lowColor
= owner
->LowColor();
69 if (IsSelected() || complete
) {
72 color
= ui_color(B_LIST_SELECTED_BACKGROUND_COLOR
);
74 color
= owner
->ViewColor();
76 owner
->SetHighColor(color
);
77 owner
->SetLowColor(color
);
78 owner
->FillRect(frame
);
80 owner
->SetLowColor(owner
->ViewColor());
82 BString text
= Text();
84 rgb_color textColor
= ui_color(B_LIST_ITEM_TEXT_COLOR
);
85 if (textColor
.red
+ textColor
.green
+ textColor
.blue
> 128 * 3)
86 owner
->SetHighColor(tint_color(textColor
, B_DARKEN_2_TINT
));
88 owner
->SetHighColor(tint_color(textColor
, B_LIGHTEN_2_TINT
));
90 text
<< " [" << B_TRANSLATE("already chosen") << "]";
93 owner
->SetHighColor(ui_color(B_LIST_SELECTED_ITEM_TEXT_COLOR
));
95 owner
->SetHighColor(ui_color(B_LIST_ITEM_TEXT_COLOR
));
99 frame
.left
+ be_control_look
->DefaultLabelSpacing() + textOffset
,
100 frame
.top
+ BaselineOffset());
101 owner
->DrawString(text
.String());
103 owner
->SetHighColor(highColor
);
104 owner
->SetLowColor(lowColor
);
111 LanguageListItemWithFlag::LanguageListItemWithFlag(const char* text
,
112 const char* id
, const char* languageCode
, const char* countryCode
)
114 LanguageListItem(text
, id
, languageCode
),
115 fCountryCode(countryCode
),
121 LanguageListItemWithFlag::LanguageListItemWithFlag(
122 const LanguageListItemWithFlag
& other
)
124 LanguageListItem(other
),
125 fCountryCode(other
.fCountryCode
),
126 fIcon(other
.fIcon
!= NULL
? new BBitmap(*other
.fIcon
) : NULL
)
131 LanguageListItemWithFlag::~LanguageListItemWithFlag()
138 LanguageListItemWithFlag::Update(BView
* owner
, const BFont
* font
)
140 LanguageListItem::Update(owner
, font
);
142 float iconSize
= Height();
143 SetWidth(Width() + iconSize
+ be_control_look
->DefaultLabelSpacing());
145 if (fCountryCode
.IsEmpty())
148 fIcon
= new(std::nothrow
) BBitmap(BRect(0, 0, iconSize
- 1, iconSize
- 1),
150 if (fIcon
!= NULL
&& BLocaleRoster::Default()->GetFlagIconForCountry(fIcon
,
151 fCountryCode
.String()) != B_OK
) {
159 LanguageListItemWithFlag::DrawItem(BView
* owner
, BRect frame
, bool complete
)
161 if (fIcon
== NULL
|| !fIcon
->IsValid()) {
162 DrawItemWithTextOffset(owner
, frame
, complete
, 0);
166 float iconSize
= fIcon
->Bounds().Width();
167 DrawItemWithTextOffset(owner
, frame
, complete
,
168 iconSize
+ be_control_look
->DefaultLabelSpacing());
170 BRect
iconFrame(frame
.left
+ be_control_look
->DefaultLabelSpacing(),
172 frame
.left
+ iconSize
- 1 + be_control_look
->DefaultLabelSpacing(),
173 frame
.top
+ iconSize
- 1);
174 owner
->SetDrawingMode(B_OP_OVER
);
175 owner
->DrawBitmap(fIcon
, iconFrame
);
176 owner
->SetDrawingMode(B_OP_COPY
);
183 LanguageListView::LanguageListView(const char* name
, list_view_type type
)
185 BOutlineListView(name
, type
),
187 fDropTargetHighlightFrame(),
188 fGlobalDropTargetIndicator(false),
189 fDeleteMessage(NULL
),
195 LanguageListView::~LanguageListView()
201 LanguageListView::ItemForLanguageID(const char* id
, int32
* _index
) const
203 for (int32 index
= 0; index
< FullListCountItems(); index
++) {
204 LanguageListItem
* item
205 = static_cast<LanguageListItem
*>(FullListItemAt(index
));
207 if (item
->ID() == id
) {
219 LanguageListView::ItemForLanguageCode(const char* code
, int32
* _index
) const
221 for (int32 index
= 0; index
< FullListCountItems(); index
++) {
222 LanguageListItem
* item
223 = static_cast<LanguageListItem
*>(FullListItemAt(index
));
225 if (item
->Code() == code
) {
237 LanguageListView::SetDeleteMessage(BMessage
* message
)
239 delete fDeleteMessage
;
240 fDeleteMessage
= message
;
245 LanguageListView::SetDragMessage(BMessage
* message
)
248 fDragMessage
= message
;
253 LanguageListView::SetGlobalDropTargetIndicator(bool isGlobal
)
255 fGlobalDropTargetIndicator
= isGlobal
;
260 LanguageListView::AttachedToWindow()
262 BOutlineListView::AttachedToWindow();
268 LanguageListView::MessageReceived(BMessage
* message
)
270 if (message
->WasDropped() && _AcceptsDragMessage(message
)) {
271 // Someone just dropped something on us
272 BMessage
dragMessage(*message
);
273 dragMessage
.AddInt32("drop_index", fDropIndex
);
274 dragMessage
.AddPointer("drop_target", this);
275 Messenger().SendMessage(&dragMessage
);
277 BOutlineListView::MessageReceived(message
);
282 LanguageListView::Draw(BRect updateRect
)
284 BOutlineListView::Draw(updateRect
);
286 if (fDropIndex
>= 0 && fDropTargetHighlightFrame
.IsValid()) {
287 // TODO: decide if drawing of a drop target indicator should be moved
289 BGradientLinear gradient
;
290 int step
= fGlobalDropTargetIndicator
? 64 : 128;
291 for (int i
= 0; i
< 256; i
+= step
)
292 gradient
.AddColor(i
% (step
* 2) == 0
293 ? ViewColor() : ui_color(B_CONTROL_HIGHLIGHT_COLOR
), i
);
294 gradient
.AddColor(ViewColor(), 255);
295 gradient
.SetStart(fDropTargetHighlightFrame
.LeftTop());
296 gradient
.SetEnd(fDropTargetHighlightFrame
.RightBottom());
297 if (fGlobalDropTargetIndicator
) {
298 BRegion
region(fDropTargetHighlightFrame
);
299 region
.Exclude(fDropTargetHighlightFrame
.InsetByCopy(2.0, 2.0));
300 ConstrainClippingRegion(®ion
);
301 FillRect(fDropTargetHighlightFrame
, gradient
);
302 ConstrainClippingRegion(NULL
);
304 FillRect(fDropTargetHighlightFrame
, gradient
);
310 LanguageListView::InitiateDrag(BPoint point
, int32 dragIndex
,
311 bool /*wasSelected*/)
313 if (fDragMessage
== NULL
)
316 BListItem
* item
= ItemAt(CurrentSelection(0));
318 // workaround for a timing problem
319 // TODO: this should support extending the selection
320 item
= ItemAt(dragIndex
);
326 // create drag message
327 BMessage message
= *fDragMessage
;
328 message
.AddPointer("listview", this);
330 for (int32 i
= 0;; i
++) {
331 int32 index
= CurrentSelection(i
);
335 message
.AddInt32("index", index
);
338 // figure out drag rect
340 BRect
dragRect(0.0, 0.0, Bounds().Width(), -1.0);
344 // figure out, how many items fit into our bitmap
345 for (int32 i
= 0, index
; message
.FindInt32("index", i
, &index
) == B_OK
;
347 BListItem
* item
= ItemAt(index
);
351 dragRect
.bottom
+= ceilf(item
->Height()) + 1.0;
354 if (dragRect
.Height() > MAX_DRAG_HEIGHT
) {
355 dragRect
.bottom
= MAX_DRAG_HEIGHT
;
361 BBitmap
* dragBitmap
= new BBitmap(dragRect
, B_RGB32
, true);
362 if (dragBitmap
->IsValid()) {
363 BView
* view
= new BView(dragBitmap
->Bounds(), "helper", B_FOLLOW_NONE
,
365 dragBitmap
->AddChild(view
);
367 BRect
itemBounds(dragRect
) ;
368 itemBounds
.bottom
= 0.0;
369 // let all selected items, that fit into our drag_bitmap, draw
370 for (int32 i
= 0; i
< numItems
; i
++) {
371 int32 index
= message
.FindInt32("index", i
);
372 LanguageListItem
* item
373 = static_cast<LanguageListItem
*>(ItemAt(index
));
374 itemBounds
.bottom
= itemBounds
.top
+ ceilf(item
->Height());
375 if (itemBounds
.bottom
> dragRect
.bottom
)
376 itemBounds
.bottom
= dragRect
.bottom
;
377 item
->DrawItem(view
, itemBounds
);
378 itemBounds
.top
= itemBounds
.bottom
+ 1.0;
380 // make a black frame around the edge
381 view
->SetHighColor(0, 0, 0, 255);
382 view
->StrokeRect(view
->Bounds());
385 uint8
* bits
= (uint8
*)dragBitmap
->Bits();
386 int32 height
= (int32
)dragBitmap
->Bounds().Height() + 1;
387 int32 width
= (int32
)dragBitmap
->Bounds().Width() + 1;
388 int32 bpr
= dragBitmap
->BytesPerRow();
391 for (int32 y
= 0; y
< height
- ALPHA
/ 2; y
++, bits
+= bpr
) {
392 uint8
* line
= bits
+ 3;
393 for (uint8
* end
= line
+ 4 * width
; line
< end
; line
+= 4)
396 for (int32 y
= height
- ALPHA
/ 2; y
< height
;
398 uint8
* line
= bits
+ 3;
399 for (uint8
* end
= line
+ 4 * width
; line
< end
; line
+= 4)
400 *line
= (height
- y
) << 1;
403 for (int32 y
= 0; y
< height
; y
++, bits
+= bpr
) {
404 uint8
* line
= bits
+ 3;
405 for (uint8
* end
= line
+ 4 * width
; line
< end
; line
+= 4)
409 dragBitmap
->Unlock();
415 if (dragBitmap
!= NULL
)
416 DragMessage(&message
, dragBitmap
, B_OP_ALPHA
, BPoint(0.0, 0.0));
418 DragMessage(&message
, dragRect
.OffsetToCopy(point
), this);
425 LanguageListView::MouseMoved(BPoint where
, uint32 transit
,
426 const BMessage
* dragMessage
)
428 if (dragMessage
!= NULL
&& _AcceptsDragMessage(dragMessage
)) {
433 BRect highlightFrame
;
435 if (fGlobalDropTargetIndicator
) {
436 highlightFrame
= Bounds();
439 // offset where by half of item height
440 BRect r
= ItemFrame(0);
441 where
.y
+= r
.Height() / 2.0;
443 int32 index
= IndexOf(where
);
445 index
= CountItems();
446 highlightFrame
= ItemFrame(index
);
447 if (highlightFrame
.IsValid())
448 highlightFrame
.bottom
= highlightFrame
.top
;
450 highlightFrame
= ItemFrame(index
- 1);
451 if (highlightFrame
.IsValid())
452 highlightFrame
.top
= highlightFrame
.bottom
;
454 // empty view, show indicator at top
455 highlightFrame
= Bounds();
456 highlightFrame
.bottom
= highlightFrame
.top
;
462 if (fDropTargetHighlightFrame
!= highlightFrame
) {
463 Invalidate(fDropTargetHighlightFrame
);
464 fDropTargetHighlightFrame
= highlightFrame
;
465 Invalidate(fDropTargetHighlightFrame
);
468 BOutlineListView::MouseMoved(where
, transit
, dragMessage
);
474 if (fDropTargetHighlightFrame
.IsValid()) {
475 Invalidate(fDropTargetHighlightFrame
);
476 fDropTargetHighlightFrame
= BRect();
478 BOutlineListView::MouseMoved(where
, transit
, dragMessage
);
483 LanguageListView::MouseUp(BPoint point
)
485 BOutlineListView::MouseUp(point
);
486 if (fDropTargetHighlightFrame
.IsValid()) {
487 Invalidate(fDropTargetHighlightFrame
);
488 fDropTargetHighlightFrame
= BRect();
494 LanguageListView::KeyDown(const char* bytes
, int32 numBytes
)
496 if (bytes
[0] == B_DELETE
&& fDeleteMessage
!= NULL
) {
497 Invoke(fDeleteMessage
);
501 BOutlineListView::KeyDown(bytes
, numBytes
);
506 LanguageListView::_AcceptsDragMessage(const BMessage
* message
) const
508 LanguageListView
* sourceView
= NULL
;
509 return message
!= NULL
510 && message
->FindPointer("listview", (void**)&sourceView
) == B_OK
;