246 lines
4.8 KiB
C++
246 lines
4.8 KiB
C++
/*
|
|
* Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
|
|
* Distributed under the terms of the MIT License.
|
|
*/
|
|
|
|
|
|
#include "GroupListView.h"
|
|
|
|
#include <map>
|
|
|
|
#include <Window.h>
|
|
|
|
|
|
class RendererLayoutItem : public BAbstractLayout {
|
|
public:
|
|
RendererLayoutItem(BView* owner, int32 index, void* item,
|
|
ListItemRenderer*& renderer)
|
|
:
|
|
fOwner(owner),
|
|
fIndex(index),
|
|
fItem(item),
|
|
fRenderer(renderer)
|
|
{
|
|
}
|
|
|
|
ListItemRenderer* Renderer() const
|
|
{
|
|
fRenderer->SetTo(fOwner, fItem);
|
|
return fRenderer;
|
|
}
|
|
|
|
int32 Index() const
|
|
{
|
|
return fIndex;
|
|
}
|
|
|
|
void* Item() const
|
|
{
|
|
return fItem;
|
|
}
|
|
|
|
virtual BSize BaseMinSize()
|
|
{
|
|
fRenderer->SetTo(fOwner, fItem);
|
|
return fRenderer->MinSize();
|
|
}
|
|
|
|
virtual BSize BasePreferredSize()
|
|
{
|
|
fRenderer->SetTo(fOwner, fItem);
|
|
return fRenderer->PreferredSize();
|
|
}
|
|
|
|
protected:
|
|
virtual void DoLayout()
|
|
{
|
|
// shouldn't ever be called?
|
|
}
|
|
|
|
private:
|
|
BView* fOwner;
|
|
int32 fIndex;
|
|
void* fItem;
|
|
ListItemRenderer*& fRenderer;
|
|
};
|
|
|
|
|
|
GroupListView::GroupListView(const char* name, GroupListModel* model,
|
|
enum orientation orientation, float spacing)
|
|
:
|
|
BView(NULL, B_WILL_DRAW, new BGroupLayout(orientation, spacing)),
|
|
fModel(NULL),
|
|
fItemRenderer(NULL),
|
|
fGroupRenderer(NULL),
|
|
fSelectionMessage(NULL)
|
|
{
|
|
SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
|
|
SetModel(model);
|
|
}
|
|
|
|
|
|
GroupListView::~GroupListView()
|
|
{
|
|
delete fModel;
|
|
delete fItemRenderer;
|
|
delete fGroupRenderer;
|
|
delete fSelectionMessage;
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::SetModel(GroupListModel* model)
|
|
{
|
|
// TODO: remove all previous
|
|
// TODO: add change mechanism
|
|
// TODO: use a "virtual" BGroupLayout (ie. one that create its layout items
|
|
// on the fly).
|
|
fModel = model;
|
|
|
|
std::map<addr_t, BGroupLayout*> groupMap;
|
|
|
|
int32 groupCount = model->CountGroups();
|
|
for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
|
|
BGroupLayout* groupItem = new BGroupLayout(B_VERTICAL, 0);
|
|
groupItem->SetVisible(false);
|
|
AddChild(groupItem);
|
|
|
|
void* group = model->GroupAt(groupIndex);
|
|
groupMap[(addr_t)group] = groupItem;
|
|
groupItem->AddItem(new RendererLayoutItem(this, groupIndex, group,
|
|
fGroupRenderer));
|
|
}
|
|
|
|
int32 itemCount = model->CountItems();
|
|
for (int itemIndex = 0; itemIndex < itemCount; itemIndex++) {
|
|
void* group = model->GroupForItemAt(itemIndex);
|
|
if (group == NULL)
|
|
continue;
|
|
|
|
BGroupLayout* groupItem = groupMap[(addr_t)group];
|
|
if (groupItem == NULL)
|
|
continue;
|
|
|
|
groupItem->SetVisible(true);
|
|
|
|
RendererLayoutItem* rendererItem = new RendererLayoutItem(this,
|
|
itemIndex, model->ItemAt(itemIndex), fItemRenderer);
|
|
groupItem->AddItem(rendererItem);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::SetItemRenderer(ListItemRenderer* renderer)
|
|
{
|
|
fItemRenderer = renderer;
|
|
InvalidateLayout();
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::SetGroupRenderer(ListItemRenderer* renderer)
|
|
{
|
|
fGroupRenderer = renderer;
|
|
InvalidateLayout();
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::SetSelectionMessage(BMessage* message, BMessenger target)
|
|
{
|
|
fSelectionMessage = message;
|
|
fSelectionTarget = target;
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::AttachedToWindow()
|
|
{
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::MessageReceived(BMessage* message)
|
|
{
|
|
switch (message->what) {
|
|
default:
|
|
BView::MessageReceived(message);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::MouseDown(BPoint point)
|
|
{
|
|
if (fSelectionMessage == NULL)
|
|
return;
|
|
|
|
BLayoutItem* item = _ItemAt(GetLayout(), point);
|
|
|
|
if (RendererLayoutItem* rendererItem
|
|
= dynamic_cast<RendererLayoutItem*>(item)) {
|
|
BMessage message(*fSelectionMessage);
|
|
|
|
int32 buttons = 0;
|
|
if (Window()->CurrentMessage() != NULL)
|
|
buttons = Window()->CurrentMessage()->FindInt32("buttons");
|
|
if (buttons != 0)
|
|
message.AddInt32("buttons", buttons);
|
|
message.AddInt32("index", rendererItem->Index());
|
|
message.AddPointer(rendererItem->Renderer() == fGroupRenderer
|
|
? "group" : "item", rendererItem->Item());
|
|
|
|
fSelectionTarget.SendMessage(&message);
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::Draw(BRect updateRect)
|
|
{
|
|
_Draw(GetLayout(), updateRect);
|
|
}
|
|
|
|
|
|
void
|
|
GroupListView::_Draw(BLayoutItem* item, BRect updateRect)
|
|
{
|
|
if (RendererLayoutItem* rendererItem
|
|
= dynamic_cast<RendererLayoutItem*>(item)) {
|
|
ListItemRenderer* renderer = rendererItem->Renderer();
|
|
renderer->Draw(this, rendererItem->Frame(), rendererItem->Index(),
|
|
false);
|
|
} else if (BLayout* layout = dynamic_cast<BLayout*>(item)) {
|
|
for (int i = 0; i < layout->CountItems(); i++) {
|
|
item = layout->ItemAt(i);
|
|
if (!item->IsVisible() || !item->Frame().Intersects(updateRect))
|
|
continue;
|
|
|
|
_Draw(item, updateRect);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
BLayoutItem*
|
|
GroupListView::_ItemAt(BLayoutItem* item, BPoint point)
|
|
{
|
|
if (RendererLayoutItem* rendererItem
|
|
= dynamic_cast<RendererLayoutItem*>(item))
|
|
return rendererItem;
|
|
|
|
if (BLayout* layout = dynamic_cast<BLayout*>(item)) {
|
|
for (int i = 0; i < layout->CountItems(); i++) {
|
|
item = layout->ItemAt(i);
|
|
if (!item->IsVisible() || !item->Frame().Contains(point))
|
|
continue;
|
|
|
|
return _ItemAt(item, point);
|
|
}
|
|
}
|
|
|
|
return item;
|
|
}
|