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