xref: /haiku/src/apps/switcher/GroupListView.cpp (revision 9a6a20d4689307142a7ed26a1437ba47e244e73f)
1 /*
2  * Copyright 2011, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "GroupListView.h"
8 
9 #include <map>
10 
11 #include <Window.h>
12 
13 
14 class RendererLayoutItem : public BAbstractLayout {
15 public:
16 	RendererLayoutItem(BView* owner, int32 index, void* item,
17 		ListItemRenderer*& renderer)
18 		:
19 		fOwner(owner),
20 		fIndex(index),
21 		fItem(item),
22 		fRenderer(renderer)
23 	{
24 	}
25 
26 	ListItemRenderer* Renderer() const
27 	{
28 		fRenderer->SetTo(fOwner, fItem);
29 		return fRenderer;
30 	}
31 
32 	int32 Index() const
33 	{
34 		return fIndex;
35 	}
36 
37 	void* Item() const
38 	{
39 		return fItem;
40 	}
41 
42 	virtual	BSize BaseMinSize()
43 	{
44 		fRenderer->SetTo(fOwner, fItem);
45 		return fRenderer->MinSize();
46 	}
47 
48 	virtual	BSize BasePreferredSize()
49 	{
50 		fRenderer->SetTo(fOwner, fItem);
51 		return fRenderer->PreferredSize();
52 	}
53 
54 protected:
55 	virtual	void DoLayout()
56 	{
57 		// shouldn't ever be called?
58 	}
59 
60 private:
61 	BView*				fOwner;
62 	int32				fIndex;
63 	void*				fItem;
64 	ListItemRenderer*&	fRenderer;
65 };
66 
67 
68 GroupListView::GroupListView(const char* name, GroupListModel* model,
69 	enum orientation orientation, float spacing)
70 	:
71 	BView(NULL, B_WILL_DRAW, new BGroupLayout(orientation, spacing)),
72 	fModel(NULL),
73 	fItemRenderer(NULL),
74 	fGroupRenderer(NULL),
75 	fSelectionMessage(NULL)
76 {
77 	SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
78 	SetModel(model);
79 }
80 
81 
82 GroupListView::~GroupListView()
83 {
84 	delete fModel;
85 	delete fItemRenderer;
86 	delete fGroupRenderer;
87 	delete fSelectionMessage;
88 }
89 
90 
91 void
92 GroupListView::SetModel(GroupListModel* model)
93 {
94 	// TODO: remove all previous
95 	// TODO: add change mechanism
96 	// TODO: use a "virtual" BGroupLayout (ie. one that create its layout items
97 	//		on the fly).
98 	fModel = model;
99 
100 	std::map<addr_t, BGroupLayout*> groupMap;
101 
102 	int32 groupCount = model->CountGroups();
103 	for (int groupIndex = 0; groupIndex < groupCount; groupIndex++) {
104 		BGroupLayout* groupItem = new BGroupLayout(B_VERTICAL, 0);
105 		groupItem->SetVisible(false);
106 		AddChild(groupItem);
107 
108 		addr_t group = model->GroupAt(groupIndex);
109 		groupMap[group] = groupItem;
110 		groupItem->AddItem(new RendererLayoutItem(this, groupIndex, (void*)group,
111 			fGroupRenderer));
112 	}
113 
114 	int32 itemCount = model->CountItems();
115 	for (int itemIndex = 0; itemIndex < itemCount; itemIndex++) {
116 		addr_t group = model->GroupForItemAt(itemIndex);
117 		if (group == 0)
118 			continue;
119 
120 		BGroupLayout* groupItem = groupMap[group];
121 		if (groupItem == NULL)
122 			continue;
123 
124 		groupItem->SetVisible(true);
125 
126 		RendererLayoutItem* rendererItem = new RendererLayoutItem(this,
127 			itemIndex, model->ItemAt(itemIndex), fItemRenderer);
128 		groupItem->AddItem(rendererItem);
129 	}
130 }
131 
132 
133 void
134 GroupListView::SetItemRenderer(ListItemRenderer* renderer)
135 {
136 	fItemRenderer = renderer;
137 	InvalidateLayout();
138 }
139 
140 
141 void
142 GroupListView::SetGroupRenderer(ListItemRenderer* renderer)
143 {
144 	fGroupRenderer = renderer;
145 	InvalidateLayout();
146 }
147 
148 
149 void
150 GroupListView::SetSelectionMessage(BMessage* message, BMessenger target)
151 {
152 	fSelectionMessage = message;
153 	fSelectionTarget = target;
154 }
155 
156 
157 void
158 GroupListView::AttachedToWindow()
159 {
160 }
161 
162 
163 void
164 GroupListView::MessageReceived(BMessage* message)
165 {
166 	switch (message->what) {
167 		default:
168 			BView::MessageReceived(message);
169 			break;
170 	}
171 }
172 
173 
174 void
175 GroupListView::MouseDown(BPoint point)
176 {
177 	if (fSelectionMessage == NULL)
178 		return;
179 
180 	BLayoutItem* item = _ItemAt(GetLayout(), point);
181 
182 	if (RendererLayoutItem* rendererItem
183 			= dynamic_cast<RendererLayoutItem*>(item)) {
184 		BMessage message(*fSelectionMessage);
185 
186 		int32 buttons = 0;
187 		if (Window()->CurrentMessage() != NULL)
188 			buttons = Window()->CurrentMessage()->FindInt32("buttons");
189 		if (buttons != 0)
190 			message.AddInt32("buttons", buttons);
191 		message.AddInt32("index", rendererItem->Index());
192 		message.AddPointer(rendererItem->Renderer() == fGroupRenderer
193 			? "group" : "item", rendererItem->Item());
194 
195 		fSelectionTarget.SendMessage(&message);
196 	}
197 }
198 
199 
200 void
201 GroupListView::Draw(BRect updateRect)
202 {
203 	_Draw(GetLayout(), updateRect);
204 }
205 
206 
207 void
208 GroupListView::_Draw(BLayoutItem* item, BRect updateRect)
209 {
210 	if (RendererLayoutItem* rendererItem
211 			= dynamic_cast<RendererLayoutItem*>(item)) {
212 		ListItemRenderer* renderer = rendererItem->Renderer();
213 		renderer->Draw(this, rendererItem->Frame(), rendererItem->Index(),
214 			false);
215 	} else if (BLayout* layout = dynamic_cast<BLayout*>(item)) {
216 		for (int i = 0; i < layout->CountItems(); i++) {
217 			item = layout->ItemAt(i);
218 			if (!item->IsVisible() || !item->Frame().Intersects(updateRect))
219 				continue;
220 
221 			_Draw(item, updateRect);
222 		}
223 	}
224 }
225 
226 
227 BLayoutItem*
228 GroupListView::_ItemAt(BLayoutItem* item, BPoint point)
229 {
230 	if (RendererLayoutItem* rendererItem
231 			= dynamic_cast<RendererLayoutItem*>(item))
232 		return rendererItem;
233 
234 	if (BLayout* layout = dynamic_cast<BLayout*>(item)) {
235 		for (int i = 0; i < layout->CountItems(); i++) {
236 			item = layout->ItemAt(i);
237 			if (!item->IsVisible() || !item->Frame().Contains(point))
238 				continue;
239 
240 			return _ItemAt(item, point);
241 		}
242 	}
243 
244 	return item;
245 }
246